【bzoj1801】[AHOI2009]中国象棋 [动态规划]
开始瓜想状压 发现n≤100压个P
分情况来讨论 利用乘法原理和加法原理
f[i][j][k]放第i行当前只有一个棋子的有j列 有两个棋子的有k列
#include<bits/stdc++.h> using namespace std; #define Max(x,y) (x)<(y)?(y):(x) #define Min(x,y) (x)<(y)?(x):(y) #define ll long long #define rg register const int N=100+5,M=1000000+5,inf=0x3f3f3f3f,P=9999973; ll n,m,ans=0,f[N][N][N]; template <class t>void rd(t &x){ x=0;int w=0;char ch=0; while(!isdigit(ch)) w|=ch=='-',ch=getchar(); while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); x=w?-x:x; } //72 89 int main(){ // freopen("in.txt","r",stdin); rd(n),rd(m); memset(f,0,sizeof(f)); f[0][0][0]=1; for(int i=0;i<n;++i) for(int j=0;j<=m;++j)//放1 for(int k=0;k<=m-j;++k){//放俩 f[i+1][j][k]=(f[i+1][j][k]+f[i][j][k])%P; if(j) f[i+1][j-1][k+1]=(f[i+1][j-1][k+1]+f[i][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]*((j-1)*j/2))%P;//放在两个有一个的列上 if(j+k+1<=m) f[i+1][j+1][k]=(f[i+1][j+1][k]+f[i][j][k]*(m-j-k))%P;//在没有棋子的放一个 if(j+k+2<=m) f[i+1][j+2][k]=(f[i+1][j+2][k]+f[i][j][k]*((m-j-k-1)*(m-j-k)/2))%P;//俩没有棋子的各放一个 if(j&&j+k+1<=m) f[i+1][j][k+1]=(f[i+1][j][k+1]+f[i][j][k]*(m-j-k)*j)%P;//一个在有一个 一个在无 } for(int i=0;i<=m;++i) for(int j=0;j<=m-i;++j) ans=(ans+f[n][i][j])%P; printf("%lld",ans); return 0; }