[AHOI2009]中国象棋

题目链接

很显然可以发现一个结论,每一行或每一列都最多只有两个棋子。

\(f[i][j][k]\)为算到第\(i\)行,有\(j\)列有一个棋子,有\(k\)列有两个棋子。

然后转移就很显然了:

设当前枚举到第\(i\)行,有\(j\)列有一个棋子,有\(k\)列有两个棋子,

若当前行不放棋子,

\[f[i+1][j][k]+=f[i][j][k]. \]

若当前行放一个棋子,

\[f[i+1][j+1][k]+=f[i][j][k]*(m-j-k). \]

\[f[i+1][j-1][k+1]+=f[i][j][k]*j. \]

若当前行放两个棋子,

\[f[i+1][j+2][k]+=f[i][j][k]*\binom{m-j-k}{2} \]

\[f[i+1][j][k+1]+=f[i][j][k]*(m-j-k)*j \]

\[f[i+1][j-2][k+2]+=f[i][j][k]*\binom{j}{2} \]

统计答案枚举几行放一个,几行放两个,加起来就好了。

#include<bits/stdc++.h>
using namespace std;
#define read(x) scanf("%lld",&x)
#define write(x) printf("%lld\n",x)
#define int long long
#define maxn 105
#define p 9999973
int f[maxn][maxn][maxn],n,m;
int calc(int x){return x*(x-1)/2;}
signed main(){
    read(n),read(m);f[0][0][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]){
            f[i+1][j][k]=(f[i+1][j][k]+f[i][j][k])%p;
            if(m-j-k>=1) f[i+1][j+1][k]=(f[i+1][j+1][k]+f[i][j][k]*(m-j-k))%p;
            if(j>=1) f[i+1][j-1][k+1]=(f[i+1][j-1][k+1]+f[i][j][k]*j)%p;
            if(m-j-k>=2) f[i+1][j+2][k]=(f[i+1][j+2][k]+f[i][j][k]*calc(m-j-k))%p;
            if(m-j-k>=1&&j>=1) f[i+1][j][k+1]=(f[i+1][j][k+1]+f[i][j][k]*(m-j-k)*j)%p;
            if(j>=2) f[i+1][j-2][k+2]=(f[i+1][j-2][k+2]+f[i][j][k]*calc(j))%p;
            //printf("%lld %lld %lld ",i,j,k);write(f[i][j][k]);
        }
    int ans=0;
    for(int i=0;i<=m;i++)
    for(int j=0;j+i<=m;j++)
        (ans+=f[n][i][j])%=p;
    write(ans);
    return 0;
}

posted @ 2018-10-25 21:44  Hyscere  阅读(99)  评论(0编辑  收藏  举报