炮(棋盘DP)
一行or一列上最多能放两个炮,因为炮会隔棋打,所以一列或者一行最多存在两个炮棋
盘的状态压为三维
dp[i][k][j]
i:棋盘的第几行 k:前i行有几列放了一个炮棋 j:前i行有几列放了两个炮棋
所以
dp方程有6个元素:
1:不放炮棋,所以方程为 dp[i][k][j]+=dp[i-1][k][j];
2:往一个没有炮棋的列放一个炮棋,方程为dp[i][j][k]+=dp[i-1][k-1][j]*(m-k-j+1);
3:往一个有一个炮棋的列放一个炮棋,方程为dp[i][j][k]+=dp[i-1][k+1][j-1]*(k+1);
4:往一个有一个炮棋的列放一个炮棋同时往一个没有炮棋的列放一个炮棋,方程为dp[i][j][k]+=dp[i-1][k][j-1]*(k)*(m-j-k+1)/2;
5:往一个有一个炮棋的列放一个炮棋同时往一个有一个炮棋的列放一个炮棋,方程为dp[i][k][j]+=(k+2)*(k+1)/2*dp[i-1][k+2][j-2];
6:往一个没有炮棋的列放一个炮棋同时往一个没有炮棋的列放一个炮棋,方程为dp[i][k][j]+=(m-j-k+2)*(m-j-k+1)/2*dp[i-1][k-2][j];
code:
kailvxiugai
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<algorithm> using namespace std; #define LL long long const int MAXN=201; const int mod=9999973; LL dp[MAXN][MAXN][MAXN]; inline int calc( int num ) { return num*(num-1)/2; } int n,m; int main() { cin>>n>>m; dp[0][0][0]=1; for(int i=0; i<n;++i) for(int j=0;j<=m;++j) for(int k=0;k+j<=m;++k) if(dp[i][j][k]) { dp[i+1][j][k]=(dp[i+1][j][k]+dp[i][j][k])%mod; if(m-j-k>=1) dp[i+1][j+1][k]=(dp[i+1][j+1][k]+dp[i][j][k]*(m-j-k))%mod; if(j>=1) dp[i+1][j-1][k+1]=(dp[i+1][j-1][k+1]+dp[i][j][k]*j)%mod; if(m-j-k>=2) dp[i+1][j+2][k]=(dp[i+1][j+2][k]+dp[i][j][k]*calc(m-j-k))%mod; if(m-j-k>=1&&j>=1) dp[i+1][j][k+1]=(dp[i+1][j][k+1]+dp[i][j][k]*(m-j-k)*j)%mod; if(j>=2) dp[i+1][j-2][k+2]=(dp[i+1][j-2][k+2]+dp[i][j][k]*calc(j))%mod; } LL ans=0; for(int i=0;i<=m;++i) for(int j=0;j<=m-i;++j) ans=(ans+dp[n][i][j])%mod; printf("%lld",ans); return 0; }