1. 程式人生 > >Luogu P2051 [AHOI2009]中國象棋

Luogu P2051 [AHOI2009]中國象棋

中國象棋 合數 strong 裏的 del 數列 amp pre gist

不得不佩服這道題的玄妙

首先我們可以發現一個顯然的性質:任意一行或任意一列至多只有兩個炮

然後就有一種50分的做法:把每一行的情況三進制狀壓,然後狀壓DP即可

轉移從上面找出所有有0個炮,1個炮,2個炮的列然後枚舉新加入的炮的個數

然後我們瞎搞一下可以發現,其實方案總數與炮擺放的位置無關

即我們根本不需要記錄炮在第幾行第幾列,直接記錄一下上一行放了0個炮,1個炮,2個炮的列數各有幾個然後就可以直接DP了

同樣可以優化,因為一行的位置都是m,因此只要知道1個炮的列數和2個炮的列數就可以用m減去他們得到0個炮的列數

因此我們設f[i][j][k]表示當前第i行,有j列有1個炮,有k列有2個炮的方案總數

則可以由f[i][j][k]推得f[i+1]的許多狀態

這裏的轉移有:

  • f[i+1][j][k]+=f[i][j][k] (一個炮也不放)

  • f[i+1][j+1][k]+=f[i][j][k]*(m-i-j)(m-j-k>=1) (在沒有炮的列上放一個炮)

  • f[i+1][j-1][k+1]+=f[i][j][k]*j(j>=1) (在只有一個炮的位置上放一個炮)

  • f[i+1][j+2][k]+=f[i][j][k]*(m-j-k)*(m-j-k-1)/2(m-j-k>=2) (在沒有炮的位置上放兩個炮,這裏的方案數要等差數列求和(組合數也可以))

  • f[i+1][j-2][k+2]+=f[i][j][k]*j*(j-1)/2(j>=2)(在有一個炮的位置上放兩個炮)

  • f[i+1][j][k+1]+=f[i][j][k]*(m-j-k)*j(m-j-k>=1&&j>=1)(在有一個炮和有沒有炮的位置上各放一個炮)

然後就很舒服了,最後求一下所有f[n+1][j][k]的和即可

邊界條件:f[1][0][0]=1;

這裏由於DP方程只需要由f[i]推得f[i+1],因此可以滾動優化然而這個數據範圍還是不需要了,但我仍然滾存了

CODE

#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
const LL N=105,mod=9999973;
LL f[2][N][N],ans;
int n,m;
inline LL C(LL x)
{
    return (x*(x-1)/2)%mod;
}
inline void inc(LL &x,LL y)
{
    if ((x+=y)>=mod) x-=mod;
}
int main()
{
    register int i,j,k;
    scanf("%d%d",&n,&m);
    f[1][0][0]=1;
    for (i=1;i<=n;++i)
    {
        int now=i&1,nxt=now^1;
        memset(f[nxt],0,sizeof(f[nxt]));
        for (j=0;j<=m;++j)
        for (k=0;j+k<=m;++k)
        if (f[now][j][k])
        {
            inc(f[nxt][j][k],f[now][j][k]);
            if (m-j-k>=1) inc(f[nxt][j+1][k],(f[now][j][k]*(m-j-k))%mod);
            if (j>=1) inc(f[nxt][j-1][k+1],(f[now][j][k]*j)%mod);
            if (m-j-k>=2) inc(f[nxt][j+2][k],(f[now][j][k]*C(m-j-k))%mod);
            if (j>=2) inc(f[nxt][j-2][k+2],(f[now][j][k]*C(j))%mod);
            if (m-j-k>=1&&j>=1) inc(f[nxt][j][k+1],(f[now][j][k]*(m-j-k)*j)%mod);
        }
    }
    for (j=0;j<=m;++j)
    for (k=0;k+j<=m;++k)
    inc(ans,f[(n+1)&1][j][k]);
    printf("%lld",ans);
    return 0;
}

Luogu P2051 [AHOI2009]中國象棋