JZOJ 1667 ( bzoj 1801 ) [ AHOI 2009 ] 中国象棋 —— DP
题目:https://jzoj.net/senior/#main/show/1667
首先,一行、一列最多只有 2 个炮;
所以记录一下之前有多少行有 0/1/2 个炮,转移即可;
注意取模!小心在某处爆 int 。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; int const maxn=105,mod=9999973; int n,m,f[maxn][maxn][maxn],ans; ll C(int x){return ((ll)x*(x-1)/2)%mod;} int main() { scanf("%d%d",&n,&m); f[m][0][0]=1; for(int i=1;i<=n;i++) for(int j=0;j<=m;j++) for(int l=m-j;l>=0;l--) { int k=m-j-l,tmp=f[j][k][l]; if(!tmp)continue; //1 if(j)(f[j-1][k+1][l]+=(ll)tmp*j)%=mod;//0 -> 1 if(k)(f[j][k-1][l+1]+=(ll)tmp*k)%=mod;//1 -> 2 //2 if(j>1)(f[j-2][k+2][l]+=(ll)tmp*C(j)%mod)%=mod;//0,0 -> 1,1 //%mod if(j&&k)(f[j-1][k][l+1]+=(ll)tmp*j%mod*k%mod)%=mod;//0,1 -> 1,2 //%mod if(k>1)(f[j][k-2][l+2]+=(ll)tmp*C(k)%mod)%=mod;//1,1 -> 2,2 //%mod } for(int j=0;j<=m;j++) for(int k=0;j+k<=m;k++) (ans+=f[j][k][m-j-k])%=mod; printf("%d\n",ans); return 0; }