[AHOI2009]中国象棋

链接

https://www.luogu.com.cn/problem/P2051

记录下第一次过省选难度的题。

题目分析

由题意可知每一列和每一行能同时存在的炮都不能超过2个,否则就会互殴。那么只需要记录每一行有1个炮的列数和有2个炮的列数递推即可。

具体做法

设状态dp[i][j][k]其中i代表行数,j代表该行有j列已经放置了一个棋子,k代表有k列已经放了2个棋子。

之后只需要对当前行放置0,1,2棵炮的情况进行递推即可

递推公式

dp[i][j][k]=dp[i-1][j][k];
if(j>=1)dp[i][j][k]+=dp[i-1][j-1][k]*(m-j-k+1);
if(k>=1)dp[i][j][k]+=dp[i-1][j+1][k-1]*(j+1);
if(j>=2)dp[i][j][k]+=dp[i-1][j-2][k]*(((m-j-k+2)*(m-j-k+1))/2);
if(k>=1)dp[i][j][k]+=dp[i-1][j][k-1]*j*(m-j-k+1);
if(k>=2)dp[i][j][k]+=dp[i-1][j+2][k-2]*(j+2)*(j+1)/2;

上代码

#include<bits/stdc++.h>
#define mod 9999973
using namespace std;
long long dp[105][105][105];
int main(){
    int n,m;
    cin>>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<=m-j;k++){
                dp[i][j][k]=dp[i-1][j][k];
                if(j>=1)dp[i][j][k]+=dp[i-1][j-1][k]*(m-j-k+1);
                if(k>=1)dp[i][j][k]+=dp[i-1][j+1][k-1]*(j+1);
                if(j>=2)dp[i][j][k]+=dp[i-1][j-2][k]*(((m-j-k+2)*(m-j-k+1))/2);
                if(k>=1)dp[i][j][k]+=dp[i-1][j][k-1]*j*(m-j-k+1);
                if(k>=2)dp[i][j][k]+=dp[i-1][j+2][k-2]*(j+2)*(j+1)/2;
                dp[i][j][k]%=mod;
            }
        }
    }
    long long ans=0;
    for(int j=0;j<=m;j++){
        for(int k=0;k<=m;k++){
            ans+=dp[n][j][k];
        //    cout<<ans<<endl;
            ans%=mod;
        }
    }
    cout<<ans;
} 

 

posted @ 2020-03-16 22:05  _LH2000  阅读(132)  评论(0编辑  收藏  举报