链接
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; }