标签:象棋 space define 大致 i++ efi cpp names 观察
给一个\(n×m\)的棋盘,在上面放若干个炮,求有多少种放置方法可以使没有一个炮可以攻击到另一个炮
状压\(dp\)
观察发现,每行和每列至多只能放\(2\)个棋子
考虑到每列中已经摆放的棋子数量会影响到之后能摆放的棋子数,不妨设:
\(f[i][j][k]\)为前\(i\)行中,一共有\(j\)列放了一个棋子的列数,\(k\)列放了两个棋子的列数
考虑这一行中放的棋子的个数
\(f[i+1][j][k] += f[i][j][k]\)
此时有一个棋子的列数会减一,有两个的列数会加一
\(f[i+1][j-1][k+1] +=f[i][j][k]×j\)
此时有一个棋子的列数会加一,有两个的列数不变
\(f[i+1][j+1][k] +=f[i][j][k]×(m-j-k)\)
此时有一个棋子的列数会加二,有两个的列数不变
\(f[i+1][j+1][k] +=f[i][j][k]×C(m-j-k)\)
此时有一个棋子的列数会减二,有两个的列数会加二
\(f[i+1][j-2][k+2] +=f[i][j][k]×C(j)\)
此时有一个棋子的列数不变,有两个棋子的列数会加一
\(f[i+1][j][k+1] +=f[i][j][k]×(m-j-k)×j\)
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 110;
#define int long long
#define mo 9999973
#define C(x) (((x)*(x-1)/2)%mo)
int f[MAXN][MAXN][MAXN];
int n,m;
signed main(){
cin>>n>>m;
f[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(f[i][j][k]){
f[i+1][j][k] = (f[i][j][k]+f[i+1][j][k])%mo;
if(j>=1) f[i+1][j-1][k+1] = (f[i+1][j-1][k+1]+f[i][j][k]*j)%mo;
if(j>=1&&(m-j-k)>0) f[i+1][j][k+1] =(f[i+1][j][k+1]+f[i][j][k]*(m-j-k)*j)%mo;
if((m-j-k)>0) f[i+1][j+1][k] = (f[i+1][j+1][k]+f[i][j][k]*(m-j-k))%mo;
if(j>=2) f[i+1][j-2][k+2] = (f[i+1][j-2][k+2]+f[i][j][k]*C(j))%mo;
if((m-j-k)>1) f[i+1][j+2][k] = (f[i+1][j+2][k]+f[i][j][k]*C(m-j-k))%mo;
}
}
}
}
int ans = 0;
for(int i=0;i<=m;i++){
for(int j=0;j+i<=m;j++){
ans = (ans+f[n][i][j])%mo;
}
}
cout<<ans%mo;
}
注意边界
转移时若不关心具体位置,考虑直接记录该状况的数量
标签:象棋 space define 大致 i++ efi cpp names 观察
原文地址:https://www.cnblogs.com/xcxc82/p/13586341.html