[BZOI1037][区间DP]生日会

我又开始正经写东西了!

最近在刷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
 2 #include
 3 #include
 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(i1][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(j1][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 } 
View Code

 

你可能感兴趣的:([BZOI1037][区间DP]生日会)