来源:互联网 发布:项羽 武力 知乎 编辑:程序博客网 时间:2024/05/01 17:36

题目描述:
众所周知,双炮叠叠将是中国象棋中很厉害的一招必杀技。炮吃子时必须
隔一个棋子跳吃,即俗称“炮打隔子”。 炮跟炮显然不能在一起打起来,于是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 longusing 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;}
1 0
原创粉丝点击