[AHOI2009]中国象棋
题目大意:
给你一个$n\times m(n,m\le100)$的棋盘,问有多少种放法使得炮不会互相攻击。
思路:
动态规划。
不难发现题目实际要求的是有多少种放法,使得每行、每列棋子不超过两个。用$f_{i,j,k}$表示前$i$行放了1个子的有$j$列,放了2个子的有$k$列。转移方程显然。
1 #include<cstdio> 2 #include<cctype> 3 typedef long long int64; 4 inline int getint() { 5 register char ch; 6 while(!isdigit(ch=getchar())); 7 register int x=ch^'0'; 8 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 9 return x; 10 } 11 const int N=101,mod=9999973; 12 int f[N][N][N]; 13 int main() { 14 const int n=getint(),m=getint(); 15 for(register int i=f[0][0][0]=1;i<=n;i++) { 16 for(register int j=0;j<=m;j++) { 17 for(register int k=0;j+k<=m;k++) { 18 f[i][j][k]=f[i-1][j][k]; 19 if(j>=1) (f[i][j][k]+=(int64)f[i-1][j-1][k]*(m-j-k+1)%mod)%=mod; 20 if(k>=1&&j+1<=m) (f[i][j][k]+=(int64)f[i-1][j+1][k-1]*(j+1)%mod)%=mod; 21 if(j>=2) (f[i][j][k]+=(int64)f[i-1][j-2][k]*(m-j-k+2)*(m-j-k+1)/2%mod)%=mod; 22 if(k>=2&&j+2<=m) (f[i][j][k]+=(int64)f[i-1][j+2][k-2]*(j+2)*(j+1)/2%mod)%=mod; 23 if(j>=1&&k>=1) (f[i][j][k]+=(int64)f[i-1][j][k-1]*(m-j-k+1)*j%mod)%=mod; 24 } 25 } 26 } 27 int ans=0; 28 for(register int j=0;j<=m;j++) { 29 for(register int k=0;j+k<=m;k++) { 30 ans=(ans+f[n][j][k])%mod; 31 } 32 } 33 printf("%d\n",ans); 34 return 0; 35 }