传送门
题目条件为同行同列最多只有两个炮。
首先,有2个炮的列实质相同。1个的和0个的也类似。
得到状态f[i][j][k]前i行j列没放,k列放了1个的方案数。
枚举转移即可。
#include<cstring>
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#define mo 999983
using namespace std;
int n,m,dp[105][105][105],c[105][3];
int dfs(int x,int y,int z){
if (x>n) return 1;
if (dp[x][y][z]) return dp[x][y][z];
dp[x][y][z]=dfs(x+1,y,z);
if (y>1) dp[x][y][z]=(dp[x][y][z]+1ll*dfs(x+1,y-2,z+2)*c[y][2])%mo;
if (y>0) dp[x][y][z]=(dp[x][y][z]+1ll*dfs(x+1,y-1,z+1)*c[y][1])%mo;
if (z>1) dp[x][y][z]=(dp[x][y][z]+1ll*dfs(x+1,y,z-2)*c[z][2])%mo;
if (z>0) dp[x][y][z]=(dp[x][y][z]+1ll*dfs(x+1,y,z-1)*c[z][1])%mo;
if (y&&z) dp[x][y][z]=(dp[x][y][z]+1ll*dfs(x+1,y-1,z)*c[y][1]*c[z][1])%mo;
return dp[x][y][z];
}
int main(){
scanf("%d%d",&n,&m);
for (int i=0;i<=m;i++) c[i][0]=1;
for (int i=1;i<=m;i++) c[i][1]=i;
for (int i=2;i<=m;i++)
c[i][2]=(c[i-1][2]+c[i-1][1])%mo;
printf("%d\n",dfs(1,m,0));
}