1801: [Ahoi2009]chess 中国象棋
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 2205 Solved: 1298
[ Submit][ Status][ Discuss]
Description
Input
Output
Sample Input
Sample Output
HINT
除了在3个格子中都放满炮的的情况外,其它的都可以.
100%的数据中N,M不超过100
50%的数据中,N,M至少有一个数不超过8
30%的数据中,N,M均不超过6
Source
题解:OTZ。。。
推想出以下6种状态:
1:在下一行什么也不放: f[i+1][j][k]=f[i+1][j][k]+f[i][j][k];
2:在下一行中找一个0个炮的列去放一个炮: f[i+1][j+1][k]=f[i+1][j+1][k]+f[i][j][k]*(m-j-k);
3:在下一行中找一个1个炮的列去放一个炮: f[i+1][j-1][k+1]=f[i+1][j-1][k+1]+f[i][j][k]*j;
4:在下一行中找两个0个炮的列去分别放一个炮: f[i+1][j+2][k]=f[i+1][j+2][k]+f[i][j][k]*(m-j-k)*(m-j-k-1)/2;
(这里运用了组合数公式,因为有m-j-k个0个炮的列,任选两个进行组合,一共有C2m-j-k种放法,化简开来就是有(m-j-k)*(m-j-k-1)/2种)
5:在下一行中找一个0个炮的列和一个1个炮的列分别去放一个炮: f[i+1][j][k+1]=f[i+1][j][k+1]+f[i][j][k]*(m-j-k)*j;
6:在下一行中找两个1个炮的列去分别放一个炮: f[i+1][j-2][k+2]=f[i+1][j-2][k+2]+f[i][j][k]*j*(j-1)/2;
最后的ans是所有的f[n]加起来: ans=ans+f[n][j][k];
代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,i,j,k;
long long ans,f[101][101][101];
int main(){
scanf("%d%d",&n,&m);
f[0][0][0]=1;
for(i=1;i<=n;i++)
for(j=0;j<=m;j++)
for(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(k&&j<m)f[i][j][k]+=f[i-1][j+1][k-1]*(j+1);
if(j>1)f[i][j][k]+=f[i-1][j-2][k]*((m-j-k+2)*(m-j-k+1)/2);
if(k>1&&j+2<=m)f[i][j][k]+=f[i-1][j+2][k-2]*((j+2)*(j+1)/2);
if(j&&k)f[i][j][k]+=f[i-1][j][k-1]*j*(m-j-k+1);
f[i][j][k]%=9999973;
}
for(i=0;i<=m;i++)
for(j=0;j<=m;j++)ans+=f[n][i][j];
printf("%lld\n",ans%9999973);
}