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;
}
原文地址:https://www.cnblogs.com/LLTYYC/p/9506719.html