bzoj1801: [Ahoi2009]chess 中国象棋

看到这种题,要么猥琐数学题,要么DP,还能搞搞什么矩乘什么的。

然后这题就是硬刚DP。很容易看出每行每列的棋子数都不超过2吧

f[i][j][k]表示枚举到第i行,有j列有1个棋子,有k列有2个棋子。然后m-j-k就可以的到没放的多少列吧。

枚举每一行,分六种情况。

1、这一行不放

2、放一个,放在没有棋子的列里

3、放一个,放在有棋子的列里

4、放两个,都放在没有棋子的列里

5、放两个,一个放在没有棋子的列里,一个放在有棋子的列里

6、放两个,都放在有棋子的列里

然后转移。方程不写了(其实代码你也看得到),推的要死要活的,丑。

 

无脑long long谢谢。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
const LL mod=9999973;
LL f[110][110][110];
int main()
{
    LL n,m;
    scanf("%lld%lld",&n,&m);
    if(n==1){printf("%lld
",1+m+m*(m-1)/2);return 0;}
    
    memset(f,0,sizeof(f));
    f[1][0][0]=1;
    f[1][1][0]=m;
    f[1][2][0]=m*(m-1)/2;
    //init
    
    LL ans=0;
    for(int i=2;i<=n;i++)
        for(int j=0;j<=m;j++)
            for(int k=0;k+j<=m;k++)
            {
                f[i][j][k]=(f[i][j][k]+f[i-1][j][k])%mod;//不放
                
                //一个 
                if(j>0)
                    f[i][j][k]=(f[i][j][k]+f[i-1][j-1][k]*(m-k-(j-1)))%mod;//没有
                if(k>0&&j<m)
                    f[i][j][k]=(f[i][j][k]+f[i-1][j+1][k-1]*(j+1))%mod;////两个    
                if(j>1)
                    f[i][j][k]=(f[i][j][k]+f[i-1][j-2][k]*(m-k-(j-2))*(m-k-(j-2)-1)/2)%mod;//没有
                if(j>0&&k>0) 
                    f[i][j][k]=(f[i][j][k]+f[i-1][j-1+1][k-1]*(m-(k-1)-j)*j)%mod;//一有一无 
                if(k>1&&j<m-1)
                    f[i][j][k]=(f[i][j][k]+f[i-1][j+2][k-2]*(j+2)*(j+1)/2)%mod;//都有 
                
                    
                if(i==n)ans=(ans+f[i][j][k])%mod;
            }
    printf("%lld
",ans);
    return 0;
}

 

原文地址:https://www.cnblogs.com/AKCqhzdy/p/8446387.html