炮
题目描述:
众所周知,双炮叠叠将是中国象棋中很厉害的一招必杀技。炮吃子时必须
隔一个棋子跳吃,即俗称“炮打隔子”。 炮跟炮显然不能在一起打起来,于是rly一天借来了许多许多的炮在棋盘上摆了起来……他想知道,在N×M的矩形方格中摆若干炮(可以不摆)使其互不吃到的情况下方案数有几种。
棋子都是相同的。
输入说明:
一行,两个正整数N和M。
输出说明:
一行,输出方案数mod 999983。
样例输入:
1 3
样例输出:
7
数据范围:
对于40%的数据,N<=4,M<=4
对于70%的数据,N<=100,M<=8
对于100%的数据,N<=100,M<=100
思路:
动态规划
状态f[i][j][k]表示前i行,放1个炮的有j列,放2个炮的有k列的方案数,那么不放炮的就有m-j-k列。
会有几种转移方式,具体看代码。
#include<iostream>
#include<cstdio>
#define lon long long
using namespace std;
const int mod=999983;
const int maxn=110;
lon n,m,f[maxn][maxn][maxn];//i j k 表示前i行,有j列放一个,k列放两个的方案数,放了0个的列为q=m-j-k
lon C(lon n,lon m)
{
lon ans=1;
for(lon i=1;i<=m;i++)
ans=ans*(n-i+1)/i,ans%=mod;
return ans;
}
int main()
{
freopen("cannon.in","r",stdin);
freopen("cannon.out","w",stdout);
scanf("%d%d",&n,&m);
f[0][0][0]=1;
for(lon i=1;i<=n;i++)
for(lon j=0;j<=m;j++)
for(lon k=0;k<=m;k++)
{
if(j+k>m) continue;
f[i][j][k]=(f[i][j][k]+f[i-1][j][k])%mod; //不放
if(j-1>=0) f[i][j][k]=(f[i][j][k]+f[i-1][j-1][k]*C(m-j-k+1,1)%mod)%mod;//在放了0个的列中,找一列放
if(j-2>=0) f[i][j][k]=(f[i][j][k]+f[i-1][j-2][k]*C(m-j-k+2,2)%mod)%mod; //在放了0个的列中,找两列放
if(j+1<=m&&k-1>=0) f[i][j][k]=(f[i][j][k]+f[i-1][j+1][k-1]*C(j+1,1)%mod);//在放了1个的列中,找一列放
if(j+2<=m&&k-2>=0) f[i][j][k]=(f[i][j][k]+f[i-1][j+2][k-2]*C(j+2,2)%mod)%mod;//在放了1个的列中,找两列放
if(k-1>=0) f[i][j][k]=(f[i][j][k]+f[i-1][j][k-1]*C(j,1)%mod*C(m-j-k+1,1)%mod)%mod;//在放了0个和放了1个的列中各找一列放
}
lon ans=0;
for(lon i=0;i<=m;i++)
for(lon j=0;j<=m;j++)
ans+=f[n][i][j];
cout<<ans%mod;
fclose(stdin);fclose(stdout);
return 0;
}