「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
Source
题解
似乎50分可以状态压缩。
正解是直接dp。。。
f[i][j][k]表示前i行有j行有一个,k行有两个
然后转移显然。
用I64d输出竟然pe了。。。
23333
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #define mod 9999973 #define ll long long using namespace std; ll f[105][105][105],ans; inline ll C(ll x){return x*(x-1)/2;} int n,m; int main() { scanf("%d%d",&n,&m); f[0][0][0]=1; for(int i=1;i<=n;i++) for(int j=0;j<=m;j++) for(int k=0;k<=m-j;k++) { f[i][j][k]=f[i-1][j][k]; if(j)f[i][j][k]+=f[i-1][j-1][k]*(m-j-k+1); if(j>1)f[i][j][k]+=f[i-1][j-2][k]*C(m-j-k+2); if(k&&j<m)f[i][j][k]+=f[i-1][j+1][k-1]*(j+1); if(j&&k)f[i][j][k]+=f[i-1][j][k-1]*(m-j-k+1)*j; if(k>1&&j<m-1)f[i][j][k]+=f[i-1][j+2][k-2]*C(j+2); f[i][j][k]%=mod; } for(int i=0;i<=m;i++) for(int j=0;j<=m-i;j++) ans+=f[n][i][j]; ans%=mod; printf("%lld",ans); return 0; } |
f[i][j][k]应该表示前i行有j列有一个炮,k列有两个
哇,学长又在虐神题了