zoukankan      html  css  js  c++  java
  • AHOI2009 中国象棋

    传送门

    这题感觉还是与什么炮兵阵地之类的很相似的……不过首先看一眼数据范围,100?这怎么状压都状压不下,再者,一个炮要考虑一整行/列,直接暴力枚举肯定做不到。

    那怎么办?首先很显然每行/列最多只能放两个炮。之后因为我们这道题首先不会统计你一共放多少个炮,二来统计的是方案数……看过dalao的题解之后,我们突然领悟到其实我们是不需要考虑当前棋盘上具体状态是什么样的。(因为要求方案数,必定枚举到所有状态)

    我们按每一行来处理,因为一行最多能放两个炮,所以就有了以下的放法。

    1.不放炮

    2.放一个炮,放置在原来没有炮的一列

    3.放一个炮,放置在原来有炮的一列

    4.放两个炮,分别放在两个原来的空列

    5.放两个炮,分别放在一个空列和一个有一个炮的一列

    6.放两个炮,分别放在两个有一个炮的空列

    当时自己特别智障,还写了一个把两个炮放在同一列的转移方程(你一行之内怎么能把两个炮放在一列)

    既然如此,我们就用dp[i][j][k]表示当前放炮到第i行,其中一共有j列有一个炮,k列有两个炮的情况数。

    那么从上到下对应上面六种情况的DP方程就是:

            if(dp[i-1][j][k])
            {
            dp[i][j][k] += dp[i-1][j][k],dp[i][j][k] %= mod;
            if(m-k-j > 0) dp[i][j+1][k] += dp[i-1][j][k] * (m-k-j),dp[i][j+1][k] %= mod;
            if(j > 0) dp[i][j-1][k+1] += dp[i-1][j][k] * j,dp[i][j-1][k+1] %= mod;
            if(m-k-j > 0 && j > 0) dp[i][j][k+1] += dp[i-1][j][k] * (m-j-k) * j,dp[i][j][k+1] %= mod;
            if(j > 1) dp[i][j-2][k+2] += dp[i-1][j][k] * c(j),dp[i][j-2][k+2] %= mod;
            if(m-k-j > 0) dp[i][j+2][k] += dp[i-1][j][k] * c(m-k-j),dp[i][j+2][k] %= mod;
            }

    其中C(x)相当于C(x,2).这样就可以做了。最后的答案是sigma{dp[n][i][j]}.

    注意初始的时候dp[0][0][0] = 1。

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<cstring>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define enter putchar('
    ')
    using namespace std;
    typedef long long ll;
    const int M = 50005;
    const int mod = 9999973;
    ll n,m,dp[105][105][105],ans; 
    ll read()
    {
        ll ans = 0,op = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
        if(ch == '-') op = -1;
        ch = getchar();
        }
        while(ch >='0' && ch <= '9')
        {
        ans *= 10;
        ans += ch - '0';
        ch = getchar();
        }
        return ans * op;
    }
    
    ll c(ll x)
    {
        return x * (x-1) / 2;
    }
    
    int main()
    {
        n = read(),m = read();
        dp[0][0][0] = 1;
        rep(i,1,n)
        {
        rep(j,0,m)
        rep(k,0,m-j)
        {
            if(dp[i-1][j][k])
            {
            dp[i][j][k] += dp[i-1][j][k],dp[i][j][k] %= mod;
            if(m-k-j > 0) dp[i][j+1][k] += dp[i-1][j][k] * (m-k-j),dp[i][j+1][k] %= mod;
            if(j > 0) dp[i][j-1][k+1] += dp[i-1][j][k] * j,dp[i][j-1][k+1] %= mod;
            //if(m-k-j > 0) dp[i+1][j][k+1] += dp[i][j][k] * (m-k-j),dp[i+1][j][k+1] %= mod;
            if(m-k-j > 0 && j > 0) dp[i][j][k+1] += dp[i-1][j][k] * (m-j-k) * j,dp[i][j][k+1] %= mod;
            if(j > 1) dp[i][j-2][k+2] += dp[i-1][j][k] * c(j),dp[i][j-2][k+2] %= mod;
            if(m-k-j > 0) dp[i][j+2][k] += dp[i-1][j][k] * c(m-k-j),dp[i][j+2][k] %= mod;
            }
        }
        }
        rep(i,0,m)
        rep(j,0,m-i) ans += dp[n][i][j],ans %= mod;
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    Robot Framework学习笔记V1.0
    新炬网络亿能测试“性能测试和自动化测试”技术研讨会
    js里面关于IE和万恶的IE6的判断
    addLoadEvent(func)有关
    js call和apply[转]
    原生AJAX
    搭建Python开发环境(含Selenium WebDriver安装)
    Python实现随机生成指定数量字符串的函数(方法)记面试问题2
    学习Question持续更新Question和Answer进度20170902
    Python数组和list的区别,tuple和set的区别记面试问题1
  • 原文地址:https://www.cnblogs.com/captain1/p/9604655.html
Copyright © 2011-2022 走看看