[AHOI2009]中国象棋
很显然可以发现一个结论,每一行或每一列都最多只有两个棋子。
设\(f[i][j][k]\)为算到第\(i\)行,有\(j\)列有一个棋子,有\(k\)列有两个棋子。
然后转移就很显然了:
设当前枚举到第\(i\)行,有\(j\)列有一个棋子,有\(k\)列有两个棋子,
若当前行不放棋子,
\[f[i+1][j][k]+=f[i][j][k].
\]
若当前行放一个棋子,
\[f[i+1][j+1][k]+=f[i][j][k]*(m-j-k).
\]
\[f[i+1][j-1][k+1]+=f[i][j][k]*j.
\]
若当前行放两个棋子,
\[f[i+1][j+2][k]+=f[i][j][k]*\binom{m-j-k}{2}
\]
\[f[i+1][j][k+1]+=f[i][j][k]*(m-j-k)*j
\]
\[f[i+1][j-2][k+2]+=f[i][j][k]*\binom{j}{2}
\]
统计答案枚举几行放一个,几行放两个,加起来就好了。
#include<bits/stdc++.h>
using namespace std;
#define read(x) scanf("%lld",&x)
#define write(x) printf("%lld\n",x)
#define int long long
#define maxn 105
#define p 9999973
int f[maxn][maxn][maxn],n,m;
int calc(int x){return x*(x-1)/2;}
signed main(){
read(n),read(m);f[0][0][0]=1;
for(int i=0;i<=n;i++)
for(int j=0;j<=m;j++)
for(int k=0;j+k<=m;k++)
if(f[i][j][k]){
f[i+1][j][k]=(f[i+1][j][k]+f[i][j][k])%p;
if(m-j-k>=1) f[i+1][j+1][k]=(f[i+1][j+1][k]+f[i][j][k]*(m-j-k))%p;
if(j>=1) f[i+1][j-1][k+1]=(f[i+1][j-1][k+1]+f[i][j][k]*j)%p;
if(m-j-k>=2) f[i+1][j+2][k]=(f[i+1][j+2][k]+f[i][j][k]*calc(m-j-k))%p;
if(m-j-k>=1&&j>=1) f[i+1][j][k+1]=(f[i+1][j][k+1]+f[i][j][k]*(m-j-k)*j)%p;
if(j>=2) f[i+1][j-2][k+2]=(f[i+1][j-2][k+2]+f[i][j][k]*calc(j))%p;
//printf("%lld %lld %lld ",i,j,k);write(f[i][j][k]);
}
int ans=0;
for(int i=0;i<=m;i++)
for(int j=0;j+i<=m;j++)
(ans+=f[n][i][j])%=p;
write(ans);
return 0;
}