[BZOJ1801][Ahoi2009]chess 中国象棋

31 篇文章 0 订阅

原题地址

第一反应状压DP,然而N≤100…

解决问题的关键在于(摘自某题解的一段话):

其实我们不用管到底哪些列有一个有两个炮,只用看到现在有几列是一个炮,有几列没有炮、两个炮

有了这个想法以后,DP方程就不难写出了【不难个鬼…细节超多OLZ】.

AC code:

#include <cstdio>
typedef long long ll;
const ll N=110;
const ll TOMOD=9999973;
ll n,m,ans;
ll f[N][N][N];

int main(){
    scanf("%lld%lld",&n,&m);
    f[0][m][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][j][k]+f[i-1][j][k])%TOMOD;
                if(k) f[i][j][k]=(f[i][j][k]+f[i-1][j+1][k-1]*(j+1))%TOMOD;
                f[i][j][k]=(f[i][j][k]+f[i-1][j][k+1]*(k+1))%TOMOD;
                if(k>1) f[i][j][k]=(f[i][j][k]+f[i-1][j+2][k-2]*(j+2)*(j+1)/2)%TOMOD;
                f[i][j][k]=(f[i][j][k]+f[i-1][j][k+2]*(k+2)*(k+1)/2)%TOMOD;
                if(k) f[i][j][k]=(f[i][j][k]+f[i-1][j+1][k]*(j+1)*k)%TOMOD;
            }
        }
    }
    for(ll i=0;i<=m;i++){
        for(ll j=0;i+j<=m;j++) ans=(ans+f[n][i][j])%TOMOD;
    }
    printf("%lld\n",ans);

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值