JZOJ 1667 ( bzoj 1801 ) [ AHOI 2009 ] 中国象棋 —— DP

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

首先,一行、一列最多只有 2 个炮;

所以记录一下之前有多少行有 0/1/2 个炮,转移即可;

注意取模!小心在某处爆 int 。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int const maxn=105,mod=9999973;
int n,m,f[maxn][maxn][maxn],ans;
ll C(int x){return ((ll)x*(x-1)/2)%mod;}
int main()
{
    scanf("%d%d",&n,&m);
    f[m][0][0]=1;
    for(int i=1;i<=n;i++)
        for(int j=0;j<=m;j++)
            for(int l=m-j;l>=0;l--)
            {
                int k=m-j-l,tmp=f[j][k][l];
                if(!tmp)continue;
                //1
                if(j)(f[j-1][k+1][l]+=(ll)tmp*j)%=mod;//0 -> 1
                if(k)(f[j][k-1][l+1]+=(ll)tmp*k)%=mod;//1 -> 2
                //2
                if(j>1)(f[j-2][k+2][l]+=(ll)tmp*C(j)%mod)%=mod;//0,0 -> 1,1 //%mod
                if(j&&k)(f[j-1][k][l+1]+=(ll)tmp*j%mod*k%mod)%=mod;//0,1 -> 1,2 //%mod
                if(k>1)(f[j][k-2][l+2]+=(ll)tmp*C(k)%mod)%=mod;//1,1 -> 2,2 //%mod
            }
    for(int j=0;j<=m;j++)
        for(int k=0;j+k<=m;k++)
            (ans+=f[j][k][m-j-k])%=mod;
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Zinn/p/9427248.html