动态规划 BZOJ1801 [Ahoi2009]chess 中国象棋

1801: [Ahoi2009]chess 中国象棋

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 1861  Solved: 1068
[Submit][Status][Discuss]

Description

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

Input

一行包含两个整数N,M,中间用空格分开.

Output

输出所有的方案数,由于值比较大,输出其mod 9999973

Sample Input

1 3

Sample Output

7

HINT

除了在3个格子中都放满炮的的情况外,其它的都可以.

100%的数据中N,M不超过100

50%的数据中,N,M至少有一个数不超过8

30%的数据中,N,M均不超过6

看起来很像状压DP的套路是不是?然而只是个很水的比较基础的DP。

满足要求的方法:每行每列棋子数不超过2,就有6种放法。

(1) 不放;(2) 放一个棋子,在之前没有棋子的一列;(3) 放一个棋子,在之前有棋子的一列;(4) 放两个棋子,在之前没有棋子的两列;(5) 放两个棋子,在之前没有棋子的一列和在之前有棋子的一列;(6) 放两个棋子,在之前有棋子的两列。

f[i][j][k]表示前i行,有j列是一个棋子,有k列是两个棋子的方案数,答案如左下

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 const int mod=9999973;
 6 using namespace std;
 7 int n,m;
 8 long long ans;
 9 long long f[110][110][110];
10 int main(){
11     scanf("%d%d",&n,&m);
12     memset(f,0,sizeof(f));
13     f[0][0][0]=1;
14     for(int i=1;i<=n;i++)
15         for(int j=0;j<=m;j++)
16             for(int k=0;k<=m-j;k++){
17                 f[i][j][k]=f[i-1][j][k];
18                 if(j>=1) f[i][j][k]=(f[i][j][k]+f[i-1][j-1][k]*(m-j-k+1))%mod;
19                 if(k>=1) f[i][j][k]=(f[i][j][k]+f[i-1][j+1][k-1]*(j+1))%mod;
20                 if(j>=2) f[i][j][k]=(f[i][j][k]+f[i-1][j-2][k]*(m-j-k+2)*(m-j-k+1)/2)%mod;
21                 if(k>=2) f[i][j][k]=(f[i][j][k]+f[i-1][j+2][k-2]*(j+2)*(j+1)/2)%mod;
22                 if(j>=1&&k>=1) f[i][j][k]=(f[i][j][k]+f[i-1][j][k-1]*(m-j-k+1)*j)%mod;
23             }
24     for(int i=0;i<=m;i++)
25         for(int j=0;j<=m-i;j++) ans=(ans+f[n][i][j])%mod;
26     printf("%lld\n",ans);
27 }
时间: 2024-08-07 22:58:59

动态规划 BZOJ1801 [Ahoi2009]chess 中国象棋的相关文章

BZOJ1801 [Ahoi2009]chess 中国象棋(DP, 计数)

题目链接 [Ahoi2009]chess 中国象棋 设f[i][j][k]为前i行,j列放了1个棋子,k列放了2个棋子的方案数 分6种情况讨论,依次状态转移. 1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define rep(i, a, b) for (int i(a); i <= (b); ++i) 6 7 typedef long long LL; 8 const LL mod = 9999973; 9 int n

bzoj1801: [Ahoi2009]chess 中国象棋 [dp]

Description 在N行M列的棋盘上,放若干个炮可以是0个,使得没有任何一个炮可以攻击另一个炮. 请问有多少种放置方法,中国像棋中炮的行走方式大家应该很清楚吧. Input 一行包含两个整数N,M,中间用空格分开. Output 输出所有的方案数,由于值比较大,输出其mod 9999973 Sample Input 1 3 Sample Output 7 HINT 除了在3个格子中都放满炮的的情况外,其它的都可以. 100%的数据中N,M不超过10050%的数据中,N,M至少有一个数不超过

bzoj1801 [Ahoi2009]chess 中国象棋

Description 在N行M列的棋盘上,放若干个炮可以是0个,使得没有任何一个炮可以攻击另一个炮. 请问有多少种放置方法,中国像棋中炮的行走方式大家应该很清楚吧. Input 一行包含两个整数N,M,中间用空格分开. Output 输出所有的方案数,由于值比较大,输出其mod 9999973 Sample Input 1 3 Sample Output 7 HINT 除了在3个格子中都放满炮的的情况外,其它的都可以. 100%的数据中N,M不超过10050%的数据中,N,M至少有一个数不超过

BZOJ1801 [Ahoi2009]chess 中国象棋 【dp】

题目 在N行M列的棋盘上,放若干个炮可以是0个,使得没有任何一个炮可以攻击另一个炮. 请问有多少种放置方法,中国像棋中炮的行走方式大家应该很清楚吧. 输入格式 一行包含两个整数N,M,中间用空格分开. 输出格式 输出所有的方案数,由于值比较大,输出其mod 9999973 输入样例 1 3 输出样例 7 提示 除了在3个格子中都放满炮的的情况外,其它的都可以. 100%的数据中N,M不超过100 50%的数据中,N,M至少有一个数不超过8 30%的数据中,N,M均不超过6 题解 一道dp题 设\

BZOJ 1801: [Ahoi2009]chess 中国象棋( dp )

dp(i, j, k)表示考虑了前i行, 放了0个炮的有j列, 放了1个炮的有k列. 时间复杂度O(NM^2) -------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const in

bzoj 1801: [Ahoi2009]chess 中国象棋

Description 在N行M列的棋盘上,放若干个炮可以是0个,使得没有任何一个炮可以攻击另一个炮. 请问有多少种放置方法,中国像棋中炮的行走方式大家应该很清楚吧. Input 一行包含两个整数N,M,中间用空格分开. Output 输出所有的方案数,由于值比较大,输出其mod 9999973 Sample Input 1 3 Sample Output 7 HINT 除了在3个格子中都放满炮的的情况外,其它的都可以. 100%的数据中N,M不超过10050%的数据中,N,M至少有一个数不超过

bzoj 1801: [Ahoi2009]chess 中国象棋【dp】

注意到一行只能放012个炮,我们只需要知道列的状态,不用状压行 所以设f[i][j][k]表示前i行有j列有1个炮,有k列有2个炮的方案数 然后分情况讨论转移就行了 #include<cstdio> #include<iostream> using namespace std; const int N=105,mod=9999973; long long n,m,f[N][N][N],ans; int main() { scanf("%lld%lld",&

【BZOJ1801】【Ahoi2009】chess 中国象棋

Time Limit: 10 Sec Memory Limit: 64 MB Description 在N行M列的棋盘上,放若干个炮可以是0个,使得没有任何一个炮可以攻击另一个炮. 请问有多少种放置方法,中国像棋中炮的行走方式大家应该很清楚吧. Input 一行包含两个整数N,M,中间用空格分开. Output 输出所有的方案数,由于值比较大,输出其mod 9999973 Sample Input 1 3 Sample Output 7 HINT 除了在3个格子中都放满炮的的情况外,其它的都可以

BZOJ 1801 AHOI 2009 chess 中国象棋 DP

题目大意:给出棋盘的大小,问任意行和列放置的棋子都不超过两个有多少种方案. 思路:一个比较麻烦的DP.f[i][j][k]表示到前i行,放置了一个棋子的列为j,放置了两个棋子的列为k的方案数,然后有六个转移: f[i][j][k] = f[i - 1][j][k] //不取 + f[i - 1][j - 1][k] * (n - (j - 1) - k) + f[i - 1][j + 1][k - 1] * (j + 1) //取一个 + f[i - 1][j - 2][k] * (n - (j