BZOJ1037 [ZJOI2008]生日聚会Party

Description

  今天是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

解题报告:

  今天考试T2,然而考场上我设计的DP是个萎的。。。

  显然DP统计方案,然而我没考虑一些奇异的情况。我的状态无法表示存在连续k个或以上的情况,所以不行。

  f[i][j][k1][k2]表示男生i个、女生j个并且[1,i]所有子序列中男生比女生多的最大数目k1、女生比男生多的最大数目k2(相当于是对于男生而言,某一个位置是男生,则标成1,女生则标成-1,求最大后缀和;女生反之。因为如果每次转移都保证之前的满足要求则只需要末尾的不超过限制就可以了。)

  然后我们每次转移的时候就考虑这次是选的是男生还是女生就可以了,注意一下边界。

  

 

 1 //It is made by jump~
 2 #include <iostream>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <cstdio>
 6 #include <cmath>
 7 #include <algorithm>
 8 #include <ctime>
 9 #include <vector>
10 #include <queue>
11 #include <map>
12 #include <set>
13 #ifdef WIN32   
14 #define OT "%I64d"
15 #else
16 #define OT "%lld"
17 #endif
18 using namespace std;
19 typedef long long LL;
20 const int MAXN = 153;
21 const int MAXK = 21;
22 const int MOD = 12345678;
23 int n,m,k,ans;
24 int f[MAXN][MAXN][MAXK][MAXK];//f[i][j][k1][k2]表示男生i个、女生j个并且[1,i]所有子序列中男生比女生多的最大数目k1、女生比男生多的最大数目k2
25 
26 inline int getint()
27 {
28        int w=0,q=0;
29        char c=getchar();
30        while((c<'0' || c>'9') && c!='-') c=getchar();
31        if (c=='-')  q=1, c=getchar();
32        while (c>='0' && c<='9') w=w*10+c-'0', c=getchar();
33        return q ? -w : w;
34 }
35 
36 inline void work(){
37     n=getint(); m=getint(); k=getint();
38     f[0][0][0][0]=1;//方案初值
39     int lin;
40     for(int i=0;i<=n;i++)
41     for(int j=0;j<=m;j++)
42         for(int k1=0;k1<=k;k1++)
43         for(int k2=0;k2<=k;k2++){//都要带等号!!!因为有的是可以在最大值时取到
44             if(!f[i][j][k1][k2]) continue;
45             //相当于是对于男生而言,某一个位置是男生,则标成1,女生则标成-1,求最大后缀和;女生反之。因为如果每次转移都保证之前的满足要求则只需要末尾的不超过限制就可以了。
46             //这一步选了一个男生
47             lin=max(k2-1,0); if(i+1<=n && k1<k) f[i+1][j][k1+1][lin]+=f[i][j][k1][k2]; if(f[i+1][j][k1+1][lin]>=MOD) f[i+1][j][k1+1][lin]%=MOD;
48             //这一步选了一个女生
49             lin=max(k1-1,0); if(j+1<=m && k2<k) f[i][j+1][lin][k2+1]+=f[i][j][k1][k2]; if(f[i][j+1][lin][k2+1]>=MOD) f[i][j+1][lin][k2+1]%=MOD;        
50         }
51     for(int i=0;i<=k;i++) for(int j=0;j<=k;j++)  { ans+=f[n][m][i][j]; if(ans>=MOD) ans%=MOD;  }
52     printf("%d",ans);
53 }
54 
55 int main()
56 {
57   work();
58   return 0;
59 }
原文地址:https://www.cnblogs.com/ljh2000-jump/p/5802995.html