DP
每行每列最多只有两个炮。发现行/列都是相同的,那么记 表示前 行有 列放了一个炮,有 列放了两个炮(记0、1、2随便两个都可以)。
考虑如下六种转移情况:
1.当前行不放炮,
2.在没有炮的其中一列放一个炮,
3.在有一个炮的其中一列放一个炮,
4.在没有炮的两列各放一个炮,
5.在有一个炮的两列各放一个炮,
6.在没有炮和有一个炮的两列各放一个炮,
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 105
#define p 9999973
#define C(x) ((x)*(x-1)>>1)
using namespace std;
typedef long long LL;
int n,m;
LL ans,f[N][N][N];
int main(){
scanf("%d%d",&n,&m);
f[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++){
(f[i][j][k]+=f[i-1][j][k])%=p;
if (j) (f[i][j][k]+=f[i-1][j-1][k]*(m-j+1-k)%p)%=p;
if (j<m&&k) (f[i][j][k]+=f[i-1][j+1][k-1]*(j+1)%p)%=p;
if (j>1) (f[i][j][k]+=f[i-1][j-2][k]*C(m-j-k+2)%p)%=p;
if (k>1&&j<m-1) (f[i][j][k]+=f[i-1][j+2][k-2]*C(j+2)%p)%=p;
if (k) (f[i][j][k]+=f[i-1][j][k-1]*(m-j-k+1)%p*j%p)%=p;
if (i==n) (ans+=f[i][j][k])%=p;
}
return printf("%lld\n",ans),0;
}