BZOJ4806포

5110 단어 DPBZOJ

Description D e s c r i p t i o n


전송문
n∗mn∗m의 바둑판이 있는데 바둑판 위에 포를 놓고 포와 포 사이에 서로 공격하지 않는 방안의 수를 묻는다.

Solution S o l u t i o n


딱 봐도 DP야.
n, m n을 보면 m은 상압 DP의 데이터 규모에 비해 비교적 크기 때문에 상압이 좋지 않다.
자세하게 분석하면 포와 포 사이에 충돌이 발생하고 소재한 줄이나 열에만 33개 이상의 포가 있다.
그리고 한 열의 포 수가 33개보다 적으면 이 두 열이 어느 위치에 있든 서로 공격하지 않는다.따라서 우리는 이 몇 개의 포의 구체적인 배치 위치를 기록할 필요가 없다. 포가 11개나 22개 놓여 있는 위치만 알면 된다. 이렇게 하면 포의 열 수가 없어도 내놓을 수 있다.
따라서 우리는 d(i, j, k)d(i, j, k)로 앞의 i행에 jj열이 11개의 포를 놓았고, k열이 22개의 포를 놓았다는 것을 나타낸다.
ii행에서 최대 두 개의 포를 놓을 수 있기 때문에 상황에 따라 상태 이동 방정식을 작성한다(상태 이동 계산은 모두 모형을 추출하는 의미에서 진행한다)
  • 불발포 d(i,j,k)=d(i,j,k)+d(i-3.1,j,k)d(i,j,k)=d(i,j,k)+d(i-4-1,j,k)
  • 포가 없는 곳에 d(i, j, k)=d(i, j, k)+d(i-3, j-1, k)∗(m-(j-1)-k)d(i, j, k)=d(i, j, k)+d(i-3, j-1, k)?(m-(j-1, k)?(m-(1)
  • 포가 있는 곳에 d(i, j, k)=d(i, j, k)+d(i-4-1, j+1, k-1)∗(i, j, k)=d(i, j, k)+d(i, j, k)+d(i--1, j+1, k-1)?(j+1)
  • 두 개의 포가 없는 곳에 각각 d(i, j, k)=d(i, j, k)+d(i-1, j-3, k)?C(m-(j-2)--k, 2)d(i, j, k)=d(i, j, k)+d(i-4-1, j-2, k)?C(m---(j-3), 912)를 넣는다.
  • 포가 없는 곳과 한 포가 있는 곳에 각각 d(i, j, k)=d(i, j, k)+d(i-3, j, k-1)?(m-j, k-1)?(i, j, k)=d(i, j, k)+d(i, j, k)+d(i-3, j-1, k-1)?(m-j-1)?(i, j-k-1)?(i, j, k-1)\87918)
  • 두 개의 포가 있는 곳에 각각 d(i, j, k)=d(i, j, k)+d(i-3, 1,j+2,k-3)를 하나씩 놓는다.
    상태 이동 방정식이 좀 많아서 세심해야 합니다.
    그리고 이 상태 이동 방정식을 살펴보면 이전의 상태와만 관련이 있다는 것을 발견하고 우리는 스크롤 그룹으로 공간을 최적화할 수 있다.

    Code C o d e

    #include
    #include
    #include
    #include
    #define MAXN 105
    #define p 999983
    #define calc(x) ((x) * ((x) - 1) / 2 % p)
    long long d[2][MAXN][MAXN];
    int main() {
        int n, m, cur = 0;
        scanf("%d%d", &n, &m);
        d[0][0][0] = 1;
        for (int i = 1; i <= n; i++) {
            cur ^= 1;
            for (int j = 0; j <= m; j++)
                for (int k = 0; k + j <= m; k++) {
                    d[cur][j][k] = d[cur ^ 1][j][k];
                    if (j >= 1) d[cur][j][k] += d[cur ^ 1][j - 1][k] * (m - (j - 1) - k);
                    if (k >= 1) d[cur][j][k] += d[cur ^ 1][j + 1][k - 1] * (j + 1);
                    if (j >= 2) d[cur][j][k] += d[cur ^ 1][j - 2][k] * calc(m - (j - 2) - k);
                    if (k >= 1) d[cur][j][k] += d[cur ^ 1][j][k - 1] * (m - j - (k - 1)) * j;
                    if (k >= 2) d[cur][j][k] += d[cur ^ 1][j + 2][k - 2] * calc(j + 2);
                    d[cur][j][k] %= p;
                }
        }
        long long ans = 0;
        for (int i = 0; i <= m; i++)
            for (int j = 0; i + j <= m; j++) 
                (ans += d[cur][i][j]) %= p;
        printf("%lld
    "
    , ans); return 0; }
  • 좋은 웹페이지 즐겨찾기