luogu P2051 [AHOI2009]中国象棋

分析:

因为这是道dp题n<=100,第一想到O(n^3)的算法,发现每行每列最多两个炮,f(i,j,k)表示放完第i行,有j列一个炮,与k列两个炮的方案。即可递推。

详细看代码。

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll MOD=9999973;
const int maxn=110;
ll f[maxn][maxn][maxn];  //f(i,j,k)表示放完第i行,有j列一个炮,与k列两个炮的方案
ll C(int n){//C(n,m) m=2
    return n*(n-1)/2%MOD;
}
int main(){
    int n,m;
    cin>>n>>m;
    f[0][0][0]=1;
    for(int i=0;i<=n;++i){
        for(int j=0;j<=m;++j){
            for(int k=0;j+k<=m;++k){
                //不放
                f[i+1][j][k]+=f[i][j][k];
                f[i+1][j][j]%=MOD;
                //放一个在有一个炮的下面
                if(j>=1){
                    f[i+1][j-1][k+1]+=f[i][j][k]*j%MOD;
                    f[i+1][j-1][k+1]%=MOD;
                }

                //放一个在没炮的下面
                if(m-j-k>=1){
                    f[i+1][j+1][k]+=f[i][j][k]*(m-j-k)%MOD;
                    f[i+1][j+1][k]%=MOD;
                } 

                //放两个一个在有炮一个在没炮
                if(m-j-k>=1&&j>=1){
                    f[i+1][j][k+1]+=f[i][j][k]*(m-j-k)*j%MOD;
                    f[i+1][j][k+1]%=MOD;
                }

                //放两个都在有炮的下面
                if(j>=2){
                    f[i+1][j-2][k+2]+=f[i][j][k]*C(j)%MOD;
                    f[i+1][j-2][k+2]%=MOD;
                }

                //放两个都在没炮的下面
                if(m-j-k>=2){
                    f[i+1][j+2][k]+=f[i][j][k]*C(m-j-k)%MOD;
                    f[i+1][j+2][k]%=MOD;
                }

            }
        }
    }
    ll ans=0;
    for(int j=0;j<=m;++j){
        for(int k=0;k+j<=m;++k){
            ans+=f[n][j][k]%MOD;
            ans%=MOD;
        }
    }
    cout<<ans;
    return 0;
}

原文地址:https://www.cnblogs.com/UnsignedNull/p/8414276.html

时间: 2024-08-29 13:10:39

luogu P2051 [AHOI2009]中国象棋的相关文章

Luogu P2051 [AHOI2009]中国象棋(dp)

P2051 [AHOI2009]中国象棋 题面 题目描述 这次小可可想解决的难题和中国象棋有关,在一个 \(N\) 行 \(M\) 列的棋盘上,让你放若干个炮(可以是 \(0\) 个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法.大家肯定很清楚,在中国象棋中炮的行走方式是:一个炮攻击到另一个炮,当且仅当它们在同一行或同一列中,且它们之间恰好 有一个棋子.你也来和小可可一起锻炼一下思维吧! 输入输出格式 输入格式: 一行包含两个整数 \(N\) , \(M\) ,之间由一个空格隔开.

Luogu P2051[AHOI2009]中国象棋【dp】By cellur925

题目传送门 题目大意:给定一个$n*m$的棋盘,求放三个"炮"使它们不共行也不共列的方案数.($n,m$$<=100$) 这题主要是转移比较困难,因为情况比较多,所以需要冷静大胆细心地进行分情况讨论. 首先我们还是设计出状态:设$f[i][j][k]$表示前$i$行,放1枚棋子的有$j$列,放2枚棋子的有$k$列的方案数. 我们这样思考:放几个?放在哪? 在第$i$行不放棋子.显然我们可以由$f[i-1][j][k]$转移过来. (f[i][j][k]+=f[i-1][j][k]

P2051 [AHOI2009]中国象棋

题目描述 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法.大家肯定很清楚,在中国象棋中炮的行走方式是:一个炮攻击到另一个炮,当且仅当它们在同一行或同一列中,且它们之间恰好 有一个棋子.你也来和小可可一起锻炼一下思维吧! 输入输出格式 输入格式: 一行包含两个整数N,M,之间由一个空格隔开. 输出格式: 总共的方案数,由于该值可能很大,只需给出方案数模9999973的结果. 输入输出样例 输入样例#

p2051 [AHOI2009]中国象棋. (bzoj 1801)

题目描述 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法.大家肯定很清楚,在中国象棋中炮的行走方式是:一个炮攻击到另一个炮,当且仅当它们在同一行或同一列中,且它们之间恰好 有一个棋子.你也来和小可可一起锻炼一下思维吧! 40pts 考试遇到了这个题,玄学打表得了\(40pts\) 玄学打表吼啊 xjb分析 正解竟然是个\(DP\)? 还有人说是状压\(DP\)?哪里来的状压啊! 前置知识 考虑到我

P2051 [AHOI2009]中国象棋[线性DP]

最近智商有点不在线.其实一直不在线. 题目 先是想用$f[i][j][k][0/1/2]$表示摆了i行时有j列空着,k列有了一个炮,且当下摆了0/1/2个的状态,转移方程写的出来但是极其繁琐.于是又设法听取评讲者题解修改状态,最后的012完全可以删去.那么仍可以表示这一行那些列摆过1个,那些列摆过0个的种类.转移时分类即可. $f[i][j][k]+=f[i-1][j][k]$ 什么都不摆 $f[i][j][k]+=(j+1)*f[i-1][j+1][k-1]$  摆1个炮 $f[i][j][k

BZOJ1801:[AHOI2009]中国象棋——题解

http://www.lydsy.com/JudgeOnline/problem.php?id=1801 https://www.luogu.org/problemnew/show/P2051 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法.大家肯定很清楚,在中国象棋中炮的行走方式是:一个炮攻击到另一个炮,当且仅当它们在同一行或同一列中,且它们之间恰好 有一个棋子.你也来和小可可一起锻炼一下思维吧

[AHOI2009]中国象棋

题目描述 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法.大家肯定很清楚,在中国象棋中炮的行走方式是:一个炮攻击到另一个炮,当且仅当它们在同一行或同一列中,且它们之间恰好 有一个棋子.你也来和小可可一起锻炼一下思维吧! 输入输出格式 输入格式: 一行包含两个整数N,M,之间由一个空格隔开. 输出格式: 总共的方案数,由于该值可能很大,只需给出方案数模9999973的结果. 输入输出样例 输入样例#

[BZOJ1801][AHOI2009]中国象棋(递推)

题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1801 分析: 只会50的状态压缩…… 然后搜了下题解,发现是dp 首先易得每行每列至多有2个棋子 设f[i][j][k]表示前i行中有j列放了1个棋子,有k列放了2个棋子,那么就有m-j-k列没有放棋子 那么下面考虑第i行放棋子情况和前i-1行放棋子状态的关系: 1.如果第i行不放棋子:f[i][j][k]+=f[i-1][j][k] 2.如果第i行放1个棋子 ①该棋子放在之前没有放

[luoguP2051] [AHOI2009]中国象棋(DP)

传送门 注释写明了一切 #include <cstdio> #define N 111 #define p 9999973 #define LL long long int n, m; LL ans, f[N][N][N]; //每一行和每一列可以放0/1/2个炮 //f[i][j][k]表示前i行放了1个炮的列有j个,放了2个炮的列有k个的方案数 //那么可以推出,放了0个炮的列有m-j-k个 inline int C(int x) { return x * (x - 1) / 2; } i