P2051 [AHOI2009]中国象棋
显然是DP
容易想到状态压缩:
按行处理,按列表示状态
状态显然,这一列放0个,放1个,放2个
然而还是不够..
继续优化
换种思路:
设f[i][j][k]表示处理到第i行,并且这i行m列中有j列放了一个棋子,k列放了2个棋子,其他的没放。
好了状态出来了转移也就好写了..
看代码就好了..可以用滚动数组,但是空间完全不是问题,而且又丑又可能写错..
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #define ll long long using namespace std; const ll mo=9999973; ll n,m; ll f[107][107][107]; inline ll C(ll x){return x*(x-1)/2;} int main() { cin>>n>>m; f[0][0][0]=1; for(ll i=1;i<=n;i++) for(ll j=0;j<=m;j++) for(ll k=0;k+j<=m;k++) { f[i][j][k]=f[i-1][j][k]; if(j>0) f[i][j][k]=(f[i-1][j-1][k]*(m-j-k+1)+f[i][j][k])%mo; if(k>0) { f[i][j][k]=(f[i-1][j+1][k-1]*(j+1)+f[i][j][k])%mo; f[i][j][k]=(f[i-1][j][k-1]*(m-j-k+1)*j+f[i][j][k])%mo; } if(k>1) f[i][j][k]=(f[i-1][j+2][k-2]*C(j+2)+f[i][j][k])%mo; if(j>1) f[i][j][k]=(f[i-1][j-2][k]*C(m-j-k+2)+f[i][j][k])%mo; //cout<<f[i][j][k]<<" "<<i<<" "<<j<<" "<<k<<endl; } ll ans=0; for(ll i=0;i<=m;i++) for(ll j=0;j+i<=m;j++) ans=(ans+f[n][i][j])%mo; cout<<ans; return 0; }