BZOJ1801 Ahoi2009 chess 中国象棋
Description
在N行M列的棋盘上,放若干个炮可以是0个,使得没有任何一个炮可以攻击另一个炮。 请问有多少种放置方法,中国像棋中炮的行走方式大家应该很清楚吧.
Input
一行包含两个整数N,M,中间用空格分开.
Output
输出所有的方案数,由于值比较大,输出其mod 9999973
Sample Input
1 3
Sample Output
7
HINT
除了在3个格子中都放满炮的的情况外,其它的都可以.
100%的数据中N,M不超过100
50%的数据中,N,M至少有一个数不超过8
30%的数据中,N,M均不超过6
不难发现每行每列最多只有2个棋子
考虑DP,
d
p
i
,
j
,
k
dp_{i,j,k}
dpi,j,k表示i行中一共有j列有一个,k列有两个
然后我们考虑这一行选多少
- 当前行不选
d p i , j , k = d p i − 1 , j , k dp_{i,j,k}=dp_{i-1,j,k} dpi,j,k=dpi−1,j,k - 当前行选一个
- 选原来是0个棋子 d p i , j , k + = d p i − 1 , j − 1 , k ∗ c n − k − j + 1 1 ( 1 ≤ j ) dp_{i,j,k}+=dp_{i-1,j-1,k}*c_{n-k-j+1}^1(1\le j) dpi,j,k+=dpi−1,j−1,k∗cn−k−j+11(1≤j)
- 选原来是1个棋子 d p i , j , k + = d p i − 1 , j + 1 , k − 1 ∗ c j + 1 1 ( 1 ≤ k , j ≤ m − 1 ) dp_{i,j,k}+=dp_{i-1,j+1,k-1}*c_{j+1}^1(1\le k,j\le m-1) dpi,j,k+=dpi−1,j+1,k−1∗cj+11(1≤k,j≤m−1)
- 当前行选两个
- 选两个原来是0的 d p i , j , k + = d p i − 1 , j − 2 , k ( 2 ≤ j ) dp_{i,j,k}+=dp_{i-1,j-2,k}(2\le j) dpi,j,k+=dpi−1,j−2,k(2≤j)
- 选两个原来是1的 d p i , j , k + = d p i − 1 , j + 2 , k − 2 ( 2 ≤ k , j ≤ m − 2 ) dp_{i,j,k}+=dp_{i-1,j+2,k-2}(2\le k,j\le m-2) dpi,j,k+=dpi−1,j+2,k−2(2≤k,j≤m−2)
- 选一个是1一个是0 d p i , j , k + = d p i − 1 , j , k − 1 ( 1 ≤ j , 1 ≤ k ( 要 保 证 原 来 有 1 ) ) dp_{i,j,k}+=dp_{i-1,j,k-1}(1\le j,1\le k(要保证原来有1)) dpi,j,k+=dpi−1,j,k−1(1≤j,1≤k(要保证原来有1))
然后就可以进行转移了
#include<bits/stdc++.h>
using namespace std;
#define fu(a,b,c) for(int a=b;a<=c;++a)
#define fd(a,b,c) for(int a=b;a>=c;--a)
#define N 110
#define LL long long
#define Mod 9999973
LL c[N][N];
LL dp[N][N][N]={0};
int n,m;
void getc(){
fu(i,0,N-1)c[i][0]=1;
fu(i,1,N-1)
fu(j,1,i)c[i][j]=(c[i-1][j]+c[i-1][j-1])%Mod;
}
LL mul(LL a,LL b){return a*b%Mod;}
int main(){
getc();
dp[0][0][0]=1;
scanf("%d%d",&n,&m);
if(n<m)swap(n,m);
fu(i,1,n)
fu(j,0,m)
fu(k,0,m-j){
dp[i][j][k]=dp[i-1][j][k];
if(j)dp[i][j][k]+=mul(dp[i-1][j-1][k],c[m-j-k+1][1]);
if(j&&k)dp[i][j][k]+=mul(dp[i-1][j][k-1],mul(j,m-j-k+1));
if(j>=2)dp[i][j][k]+=mul(dp[i-1][j-2][k],c[m-j-k+2][2]);
if(k>=1&&j<=m-1)dp[i][j][k]+=mul(dp[i-1][j+1][k-1],c[j+1][1]);
if(k>=2&&j<=m-2)dp[i][j][k]+=mul(dp[i-1][j+2][k-2],c[j+2][2]);
dp[i][j][k]%=Mod;
}
int ans=0;
fu(i,0,m)
fu(j,0,m-i)
ans=(ans+dp[n][i][j])%Mod;
printf("%d",ans);
return 0;
}