[BZOI1037]生日会
我又开始正经写东西了!
最近在刷DP题,节奏比较紧张,一直抽不出什么时间写总结。但是今天这道题实在神奇,真的值得写一写。
题目
今天是hidadz小朋友的生日,她邀请了许多朋友来参加她的生日party。 hidadz带着朋友们来到花园中,打算坐成一排玩游戏。为了游戏不至于无聊,就座的方案应满足如下条件:对于任意连续的一段,男孩与女孩的数目之差不超过k。很快,小朋友便找到了一种方案坐了下来开始游戏。hidadz的好朋友Susie发现,这样的就座方案其实是很多的,所以大家很快就找到了一种,那么到底有多少种呢?热爱数学的hidadz和她的朋友们开始思考这个问题…… 假设参加party的人中共有n个男孩与m个女孩,你是否能解答Susie和hidadz的疑问呢?由于这个数目可能很多,他们只想知道这个数目除以12345678的余数。
Input
仅包含一行共3个整数,分别为男孩数目n,女孩数目m,常数k。
Output
应包含一行,为题中要求的答案。
Sample Input
1 2 1
Sample Output
1
Hint
n , m ≤ 150,k ≤ 20。
解说
为什么说这个东西神奇呢?因为这是我目前碰到的dp数组维数最多的DP题,它需要四维数组!
为什么会需要四维呢?我们来看一下题目里面有哪些需要枚举的量。首先男生女生人数是必须的。之后就是男女生人数之差,这会需要枚举两个量,男生比女生多出的人数,或者女生比男生多出的人数(因为数组下标不能为负嘛),这样就是有四个需要枚举的变量。枚举的时候就开四重循环,前两个代表男女生人数,从0分别循环到n和m;后两个代表差,从零循环到k。
注意:
1.从零开始循环,因为可能全男可能全女也可能男女相等
2.枚举人数差时要加上max(0,人数差)避免负数
代码
1 #include<cstdio>
2 #include<cmath>
3 #include<algorithm>
4 using namespace std;
5 int f[155][155][25][25];
6 int main(){
7 int N,M,p;
8 scanf("%d%d%d",&N,&M,&p);
9 f[0][0][0][0]=1;
10 for(int i=0;i<=N;i++){
11 for(int j=0;j<=M;j++){
12 for(int k=0;k<=p;k++){
13 for(int l=0;l<=p;l++){
14 if(!f[i][j][k][l]) continue;
15 if(i<N&&k<p) f[i+1][j][k+1][max(l-1,0)]=(f[i+1][j][k+1][max(l-1,0)]+f[i][j][k][l])%12345678;
16 if(j<M&&l<p) f[i][j+1][max(k-1,0)][l+1]=(f[i][j+1][max(k-1,0)][l+1]+f[i][j][k][l])%12345678;
17 }
18 }
19 }
20 }
21 int ans=0;
22 for(int i=0;i<=p;i++)
23 for(int j=0;j<=p;j++)
24 ans=(ans+f[N][M][i][j])%12345678;
25 printf("%d",ans);
26 return 0;
27 }
幸甚至哉,歌以咏志。
签名:
我将轻轻叹息,叙述这一切,
许多许多年以后:
林子里有两条路,我——
选择了行人稀少的那一条,
它改变了我的一生。