cqx에서 온 dp신제.

3670 단어 file2010
요 며칠 갑자기 cqx의 dp문제가 생각났는데 매우 어려운 것 같다.어차피 할 일이 없어서 했다.그리고 완전히 학대당했어요...
제목은shtsc2010, 무도회에서 유래했다.제목은 n명의 남자의 키를 B[i], n명의 여자의 키를 G[i]로 정하고 몇 가지 조합 방식을 구하여 많은 k의 댄서 파트너 사이에서 여자가 남자보다 높게 만든다는 뜻이다.
cqx는 두 가지 dp방식이 있는데, 나는 첫 번째 방식에 따라 dp를 한다.
현재 B[i], G[i]의 승차 순서를 정하고 상태 f[i, j]를 남녀 각 전 i개인으로 정의한다. 여자가 남자보다 키가 큰 j의 댄서 파트너 수는 k의 방안 수이다.
명령 Gk = min {k|1 <=k <=i, G[Gk]> B[i]}, Bk = min {k|1 <=k <=i, B[Bk]>= G[i]}, 하나는 등호가 있는지 주의해라.
먼저 쓰기 전이 방정식: f[i][j] = f[i-1] [j-(B[i] < G[i])] + (i-j + Bk - Gk)* f[i-1] [j-1] + (j-Bk + Gk)* f[i-1] [j].못 알아보겠어?괜찮아, 이 문제는 어려우면 옮기기 어려워, 이 옮기는 것도 하나의 경지가 되기 어려워.
밤새 이동을 미루며 몇 개의 양을 헤매다.미치겠네.
오늘 아침에 오자마자 계속 밀고 옮겼는데, 마침내 내 AC에 의해 떨어졌다.
이동은 다음과 같습니다.
1. B[i]와 G[i]를 짝짓기;
이때 원래의 것은 모두 j-(B[i]2. B[k]>G[i]로 하여금 G와 B의 단조성을 토대로 B[i]>B[k]>G[i]>G[k]를 B[k]와 바꾸면 서로 바꾼 후에 모두 0쌍이 여자를 남자보다 크게 한다. 이때 f[i][j]는 f[i][j]에서 f[i][j]로 옮긴다. k는 모두 i-Bk개가 있기 때문에 f[i][j]는 반드시 (i-Bk)*f[i-1]를 추가해야 한다.
3. G[k]>B[i]로 하여금 같은 이치로 얻을 수 있다. 여자가 남자보다 높은 대수는 1->2이기 때문에 f[i-1][j-1]에서 옮기면 k는 모두 i-Gk개가 있다.
4. 만약에 B[k]B[i]를 만족시키는 k는 것은 모두 i-Gk개이기 때문에 조건을 만족시키는 k는 모두 j-(i-Gk)개가 있다.
5. 만약에 G[k]위에서 말한 것을 종합하면 모두 합치면 f[i][j]의 전이 표현식을 얻을 수 있다.
cqx가 너무 부도덕해서 고정(사실은 두 번째 방법을 끊기 위해서)까지 써야 하기 때문에 머리가 어지럽고 사지에 힘이 없어서 짜증나 죽겠어요.
마지막으로 예제에 따라 코드를 붙입니다.
#include 
#include 
#include 

#define maxlen 100
#define maxn   205
#define base   1000000

typedef int bn[maxlen];

bn buf;
bn dp[maxn][maxn];
int B[maxn];
int G[maxn];

void add (bn p, bn q, int k)
{
  if (!k || !q[0] || !q[q[0]]) return;
  bn x;
  int i;
  memset (x, 0, sizeof (x));
  x[0] = p[0] > q[0] ? p[0] : q[0];
  for (i = 1; i <= x[0]; ++i)
    x[i] = p[i] + q[i] * k;
  for (i = 1; i <= x[0]; ++i)
    if (x[i] >= base)
      x[i + 1] += x[i] / base, x[i] %= base;
  if (x[x[0] + 1]) ++x[0];
  memcpy (p, x, sizeof (bn));
}

int cmper (const void *i, const void *j)
{
  return *(int *)i - *(int *)j;
}

int main()
{
  FILE *fin  = fopen ("ball.in" , "r");
  FILE *fout = fopen ("ball.out", "w");

  int n, k, Gk = 0, Bk = 0, i, j;
  bn ans;

  fscanf (fin, "%d%d", &n, &k);
  for (i = 1; i <= n; ++i)
    fscanf (fin, "%d", &B[i]);
  for (i = 1; i <= n; ++i)
    fscanf (fin, "%d", &G[i]);
  qsort (B + 1, n, sizeof (B[0]), cmper);
  qsort (G + 1, n, sizeof (G[0]), cmper);

  dp[0][0][0] = 1, dp[0][0][1] = 1;
  for (i = 1; i <= n; ++i)
    {
      for (; G[Gk] <= B[i] && Gk < i; ++Gk);
      for (; B[Bk] <  G[i] && Bk < i; ++Bk);
      for (j = i - Gk; j <= Bk; ++j)
        {
          memcpy (dp[i][j], dp[i - 1][j - (B[i] < G[i])], sizeof (bn));
          add (dp[i][j], dp[i - 1][j - 1], i - j + Bk - Gk);
          add (dp[i][j], dp[i - 1][j    ],     j - Bk + Gk);
        }
    }

  memset (ans, 0, sizeof (ans));
  for (i = 0; i <= k; ++i)
    add (ans, dp[n][i], 1);
  
  fprintf (fout, "%d", ans[ans[0]]);
  for (; --ans[0] > 0; )
    fprintf (fout, "%06d", ans[ans[0]]);

  fclose (fin);
  fclose (fout);
  return 0;
}

좋은 웹페이지 즐겨찾기