[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 }

 

posted @ 2018-03-17 10:09  skylee03  阅读(117)  评论(0编辑  收藏  举报