JZOJ 1667【AHOI2009】中国象棋——dp

题目:https://jzoj.net/senior/#main/show/1667

只注重0、1、2的列有多少个,不注重它们的位置,就能记录了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=105,mod=9999973;
int n,m,dp[2][N][N][N],ans,jc[N],jcn[N];
int pw(int x,int k)
{
    int ret=1;while(k){if(k&1)ret=(ll)ret*x%mod;x=(ll)x*x%mod;k>>=1;}return ret;
}
void init()
{
    jc[0]=1;
    for(int i=1;i<=m;i++)jc[i]=(ll)jc[i-1]*i%mod;/////m not n
    jcn[m]=pw(jc[m],mod-2);
    for(int i=m-1;i>=0;i--)jcn[i]=(ll)jcn[i+1]*(i+1)%mod;
}
int C(int n,int m)
{
    return (ll)jc[n]*jcn[m]%mod*jcn[n-m]%mod;
}
int main()
{
    scanf("%d%d",&n,&m);dp[0][m][0][0]=1;
    init();
    for(int i=1;i<=n;i++)
    {
        int d=(i&1);
        for(int x=0;x<=m;x++)
            for(int y=0;y<=m;y++)
            {
                int z=m-x-y;
                dp[d][x][y][z]=dp[!d][x][y][z];
                if(y)(dp[d][x][y][z]+=(ll)dp[!d][x+1][y-1][z]*(x+1)%mod)%=mod;//0->1
                if(z)(dp[d][x][y][z]+=(ll)dp[!d][x][y+1][z-1]*(y+1)%mod)%=mod;//1->2
                if(y>1)(dp[d][x][y][z]+=(ll)dp[!d][x+2][y-2][z]*C(x+2,2)%mod)%=mod;//0,0->1,1
                if(y&&z)(dp[d][x][y][z]+=(ll)dp[!d][x+1][y][z-1]*(x+1)%mod*y%mod)%=mod;//0,1->1,2
                if(z>1)(dp[d][x][y][z]+=(ll)dp[!d][x][y+2][z-2]*C(y+2,2)%mod)%=mod;//1,1->2,2
            }
    }
    int d=(n&1);
    for(int x=0;x<=m;x++) for(int y=0;y<=m;y++) (ans+=dp[d][x][y][m-x-y])%=mod;
    printf("%d\n",ans);
    return 0;
}

 

posted on 2018-08-05 21:22  Narh  阅读(178)  评论(0编辑  收藏  举报

导航