首页 > 代码库 > BZOJ 4806 : 炮

BZOJ 4806 : 炮

题目链接

题意:炮在同一行或是同一列超过三个就可以出现一个吃掉另一个的情况,求在n*m的棋盘上放置炮且两两不可吃的情况总数。

用dp的方法来完成计数,可以考虑这样一个状态,枚举到第x行,共有 a个“含2个炮的列”, b个“含1个炮的列”, c个“含0个炮的列”,注意到a+b+c等于定值,显然这是可以优化的。基本思路大概这样。

 

dp[i][j][k]表示前i行里,具有{有j个“含1个炮的列”, k个“含2个炮的列”}性质的情况总数

最后求ans时,要对dp[n][][]求总和

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;

const int mod=999983;
const int N=105;

int n,m;
LL dp[N][N][N];

int cal(int x)
{
    return x*(x-1)/2%mod;
}

int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        dp[0][0][0]=1;
        for(int i=1;i<=n;i++)
            for(int j=0;j<=m;j++)
                for(int k=0;k+j<=m;k++)
                {
                    dp[i][j][k]=dp[i-1][j][k];
                    if(j>=1) dp[i][j][k]=(dp[i][j][k]+dp[i-1][j-1][k]*(m-k-j+1))%mod;
                    if(j>=2) dp[i][j][k]=(dp[i][j][k]+dp[i-1][j-2][k]*cal(m-k-j+2))%mod;
                    if(k>=1) dp[i][j][k]=(dp[i][j][k]+dp[i-1][j+1][k-1]*(j+1))%mod;
                    if(k>=1) dp[i][j][k]=(dp[i][j][k]+dp[i-1][j][k-1]*(m-k-j+1)%mod*j)%mod;
                    if(k>=2) dp[i][j][k]=(dp[i][j][k]+dp[i-1][j+2][k-2]*cal(j+2))%mod;
                }
        int ans=0;
        for(int i=0;i<=m;i++)
            for(int j=0;i+j<=m;j++)
                ans=(ans+dp[n][i][j])%mod;
        printf("%d\n",ans);
    }
}

 

BZOJ 4806 : 炮