bzoj 1801 [AHOI2009]中国象棋

先扔一波链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1801
这道题刚看时感觉还是挺……以为是到数学题,lhy大佬给我提供了思路,在这里表示感谢
下面来说说吧。
题目的意思无非就是说每行每列只能放最多两个棋子的方案数。
首先我们可以设一个三维dp的状态:f[i][j][k]表示前i行,有j行是放了一个棋子的,有k行是放了连个棋子的。
然后就可以开心地转移了

#include<bits/stdc++.h>
#define mod 9999973
using namespace std;
long long n,m,f[105][105][105],ans;
int main(){
    scanf("%lld%lld",&n,&m);
    f[0][0][0]=1;
    for(long long i=0;i<=n-1;i++)
        for(long long j=0;j<=m;j++)
            for(long long k=0;k+j<=m;k++){
            //i+1行蛤都不放
                f[i+1][j][k]=(f[i+1][j][k]+f[i][j][k])%mod;
            //在那一列蛤都没有的那里放
                f[i+1][j+1][k]=(f[i+1][j+1][k]+(m-j-k)*f[i][j][k])%mod;
            //在那一列有一个的那里放
                if(j>=1) f[i+1][j-1][k+1]=(f[i+1][j-1][k+1]+(j*f[i][j][k]))%mod;
            //以上是放一个的,现在是放两个的(因为要一行一行放嘛……)这里就是表示放的两个都是所在的列上一个也没有的
                f[i+1][j+2][k]=(f[i+1][j+2][k]+(m-j-k)*(m-j-k-1)/2*f[i][j][k])%mod;
            //这是所在的列上有一个的
                if(j>=2) f[i+1][j-2][k+2]=(f[i+1][j-2][k+2]+j*(j-1)/2*f[i][j][k])%mod;
            //所在的列一个有一个,一个有两个的
                if(j>=1) f[i+1][j][k+1]=(f[i+1][j][k+1]+(m-j-k)*j*f[i][j][k])%mod;
            }
        for(int i=0;i<=m;i++)
            for(int j=0;j+i<=m;j++)
                ans=(ans+f[n][i][j])%mod;
        printf("%lld",ans);
    return 0;
}

啊♂

posted @ 2018-08-18 14:49  lahlah  阅读(17)  评论(0编辑  收藏  举报