zoukankan      html  css  js  c++  java
  • [bzoj1801][Ahoi2009]chess 中国象棋

    来自FallDream的博客,未经允许,请勿转载, 谢谢。


    在N行M列的棋盘上,放若干个炮可以是0个,使得没有任何一个炮可以攻击另一个炮。 请问有多少种放置方法,中国像棋中炮的行走方式大家应该很清楚吧.

    n,m<=100

    直接状压dp不可能了

    但是发现所有的列只有放了几个会影响答案,它是哪列无所谓,转移都相同。

    所以可以用f[i][j][k]表示前i行有j个列没放,k个列放了1个的状态数,转移的时候计算一下这么转移的方案数即可。

    #include<iostream>
    #include<cstdio>
    #define MN 100
    #define mod 9999973
    #define ll long long
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    
    int f[MN+5][MN+5][MN+5],n,m;
    inline void R(int&x,ll y){x=(1LL*x+y)%mod;}
    int main()
    {
        n=read();m=read();
        f[0][m][0]=1;
        for(int i=1;i<=n;++i)
            for(int j=0;j<=m;++j) 
                for(int k=0;k<=m;++k)
                    if(f[i-1][j][k])
                    {
                        if(j>0) R(f[i][j-1][k+1],1LL*j*f[i-1][j][k]);
                        if(j>1) R(f[i][j-2][k+2],1LL*j*(j-1)/2*f[i-1][j][k]);
                        if(k>0) R(f[i][j][k-1],1LL*k*f[i-1][j][k]);
                        if(k>1) R(f[i][j][k-2],1LL*k*(k-1)/2*f[i-1][j][k]);
                        if(j&&k)R(f[i][j-1][k],1LL*j*k*f[i-1][j][k]);
                        R(f[i][j][k],f[i-1][j][k]);
                    }
        int ans=0;
        for(int j=0;j<=m;++j)
            for(int k=0;k<=m;++k)
                R(ans,f[n][j][k]);
        printf("%d
    ",ans);        
        return 0;
    }
  • 相关阅读:
    网络系列之
    网络系列之
    Linux命令系列之
    Linux命令系列之
    Linux命令系列之
    Linux命令系列之
    Linux命令系列之
    Linux命令系列之
    Linux命令系列之
    Linux命令系列之
  • 原文地址:https://www.cnblogs.com/FallDream/p/bzoj1801.html
Copyright © 2011-2022 走看看