【bzoj1801】[AHOI2009]中国象棋 [动态规划]

2051 [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;
}

 

posted @ 2019-07-18 08:35  委屈的咸鱼鱼鱼鱼  阅读(157)  评论(0编辑  收藏  举报