[AHOI 2009] 中国象棋

题目传送-Luogu2051

题目传送-BZOJ1801

题意:

给一个n*m的棋盘,要求每一行列只能有不超过3个棋子,问方案数(棋子数任意)
\(n,m \le 100\)

题解:

这题唯一的脑洞之处就只有状态了
观察到每一行/列最多只能有2个,在这上面做手脚
设置\(f_{i,j,k}\)表示前i行完成,还有j列可以放2个,k列可以放1个
转移显然

过程:

很顺利,除了状态想了一会儿

代码:

const int N=110;
const ll P=9999973;
int n,m;
ll f[N][N][N],C[N][N],ans;
signed main() {
    read(n); read(m);
    for(int i=0;i<=100;i++) C[i][0]=1;
    for(int i=1;i<=100;i++)
        for(int j=1;j<=i;j++)
            C[i][j]=(C[i-1][j-1]+C[i-1][j])%P;
    f[0][m][0]=1;
    for(int i=0;i<n;i++)
        for(int j=0;j<=m;j++)
            for(int k=0;j+k<=m;k++)
                if(f[i][j][k]) {
                    ll val=f[i][j][k];
                    (f[i+1][j][k]+=val)%=P;// NUL
                    if(j) (f[i+1][j-1][k+1]+=val*j)%=P;//j
                    if(k) (f[i+1][j][k-1]+=val*k)%=P;//k
                    if(j) (f[i+1][j-1][k]+=val*j%P*k%P)%=P;//j k
                    if(j>1) (f[i+1][j-2][k+2]+=val*C[j][2])%=P;
                    if(k>1) (f[i+1][j][k-2]+=val*C[k][2])%=P;
                }
    for(int i=0;i<=m;i++)
        for(int j=0;i+j<=m;j++)
            (ans+=f[n][i][j])%=P;
    printf("%lld\n",ans);
    return 0;
}

用时:15

猜你喜欢

转载自www.cnblogs.com/functionendless/p/9444533.html
今日推荐