题目:https://www.luogu.org/problem/P2051
定义d[i][j][k]为前i行中,恰好有j列各放1颗棋子,k列各放2颗棋子时的方案数。
阶段、状态、转移方程及决策见代码。
边界:f[0][0][0]=1。
注意:
1、开long long,不要开int,否则会爆int。当然,可以在每乘一个数时就取模,但那样比较繁琐。
2、务必找些样例检验,比如:
样例1
3 1
答案是7。
样例2
2 2
答案是16。
AC代码:
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=101,MOD=9999973;
long long n,m,d[101][101][101],ans;//用long long,否则卡6个点
int main(){
cin>>n>>m;
d[0][0][0]=1;//初始化
for(int i=1;i<=n;i++)//阶段
for(int j=0;j<=m;j++)//状态
for(int k=0;j+k<=m;k++){//下面各行注意j,k的变化
//第i行不放棋子
d[i][j][k]=(d[i][j][k]+d[i-1][j][k])%MOD;
//第i行放1颗棋子,放在前i-1行没有放棋子的列
if(j>=1)d[i][j][k]=(d[i][j][k]+d[i-1][j-1][k]*(m-j+1-k))%MOD;
//第i行放1颗棋子,放在前i-1行放1颗棋子的列
if(k>=1)d[i][j][k]=(d[i][j][k]+d[i-1][j+1][k-1]*(j+1))%MOD;
//第i行放2颗棋子,放在前i-1行没有放棋子的列
if(j>=2)d[i][j][k]=(d[i][j][k]+d[i-1][j-2][k]*(m-j+2-k)*(m-j+1-k)/2)%MOD;
//第i行放2颗棋子,1颗放在前i-1行没有放棋子的列,1颗放在放1颗棋子的列
if(k>=1)d[i][j][k]=(d[i][j][k]+d[i-1][j][k-1]*(m-j-k+1)*j)%MOD;
//第i行放2颗棋子,全放在前i-1行放1颗棋子的列
if(k>=2)d[i][j][k]=(d[i][j][k]+d[i-1][j+2][k-2]*(j+2)*(j+1)/2)%MOD;
}
for(int j=0;j<=m;j++)
for(int k=0;k+j<=m;k++)
ans=(ans+d[n][j][k])%MOD;
cout<<ans;
return 0;
}