P2051 [AHOI2009]中国象棋 DP
题目描述
这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法。大家肯定很清楚,在中国象棋中炮的行走方式是:一个炮攻击到另一个炮,当且仅当它们在同一行或同一列中,且它们之间恰好 有一个棋子。你也来和小可可一起锻炼一下思维吧!
输入输出格式
输入格式:
一行包含两个整数N,M,之间由一个空格隔开。
输出格式:
总共的方案数,由于该值可能很大,只需给出方案数模9999973的结果。
输入输出样例
说明
样例说明
除了3个格子里都塞满了炮以外,其它方案都是可行的,所以一共有2*2*2-1=7种方案。
数据范围
100%的数据中N和M均不超过100
50%的数据中N和M至少有一个数不超过8
30%的数据中N和M均不超过6
思路:f[i][j][k]代表填满i行时有j列有一个棋子,k列有2个棋子的方案数,枚举当前行填棋子的个数及位置可以很快得出转移方程。
代码:
1 #include"bits/stdc++.h" 2 #define db double 3 #define ll long long 4 #define vec vector<ll> 5 #define Mt vector<vec> 6 #define ci(x) scanf("%d",&x) 7 #define cd(x) scanf("%lf",&x) 8 #define cl(x) scanf("%lld",&x) 9 #define pi(x) printf("%d\n",x) 10 #define pd(x) printf("%f\n",x) 11 #define pl(x) printf("%lld\n",x) 12 #define rep(i, n) for(int i=0;i<n;i++) 13 using namespace std; 14 const int N = 1e6 + 5; 15 const int mod = 1e9 + 7; 16 const int MOD = 9999973; 17 const int inf = 0x3f3f3f3f; 18 const db PI = acos(-1.0); 19 const db eps = 1e-10; 20 ll f[105][105][105]; 21 int n,m; 22 ll C(int x) 23 { 24 return 1ll*x*(x-1)/2%MOD; 25 } 26 int main() 27 { 28 ci(n),ci(m); 29 memset(f,0, sizeof(f)); 30 f[0][0][0]=1; 31 for(int i=0;i<n;i++){ 32 for(int j=0;j<=m;j++){ 33 for(int k=0;k+j<=m;k++){ 34 if(f[i][j][k]!=0){ 35 f[i+1][j][k]=(f[i+1][j][k]+f[i][j][k])%MOD; 36 if(m-k-j>=1) f[i+1][j+1][k]=(f[i+1][j+1][k]+(m-k-j)*f[i][j][k]%MOD)%MOD; 37 if(j>=1) f[i+1][j-1][k+1]=(f[i+1][j-1][k+1]+j*f[i][j][k]%MOD)%MOD; 38 if(m-k-j>=2) f[i+1][j+2][k]=(f[i+1][j+2][k]+C(m-k-j)*f[i][j][k]%MOD)%MOD; 39 if(j>=2) f[i+1][j-2][k+2]=(f[i+1][j-2][k+2]+C(j)*f[i][j][k]%MOD)%MOD; 40 if(j>=1&&m-k-j>=1) f[i+1][j][k+1]=(f[i+1][j][k+1]+j*(m-k-j)*f[i][j][k]%MOD)%MOD; 41 } 42 } 43 } 44 } 45 ll ans=0; 46 for(int j=0;j<=m;j++){ 47 for(int k=0;k+j<=m;k++){ 48 ans=(ans+f[n][j][k])%MOD; 49 } 50 } 51 pl(ans); 52 }