[BZOJ5046]分糖果游戏

题目大意:
  有a,b两个人分糖,每个人都有一个能量值。
  每个人每一轮可以选择进行两种操作:
    1.取走最左边的糖果,补充相应的能量值并获取相应的美味度。
    2.跳过这一轮,能量值-1.
  问在每个人都采取最优决策的情况下,每个人能获得最多的美味度是多少?

思路:
  动态规划。
  f[i][j]表示吃第i~n的糖,并获得j的美味度,两人能量值之差最小是多少。
  如果轮到的人选择吃,那么f[i][j]=-f[i+1][suf[i]-j+1]-r[i]+1;
  如果不吃,那么f[i][j]=max(f[i+1][j]+r[i]+1,1)。
  不吃的时候要满足能量值之差>=1,因为对方同样可以通过不吃补回来。
  最后的答案k为满足f[0][k]<=a-b的最大值,糖果最后一定能吃完,所以只要减一下就得到了两个答案。

 1 #include<cstdio>
 2 #include<cctype>
 3 #include<algorithm>
 4 typedef long long int64;
 5 inline int getint() {
 6     register char ch;
 7     while(!isdigit(ch=getchar()));
 8     register int x=ch^'0';
 9     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
10     return x;
11 }
12 const int64 inf=0x4000000000000000ll;
13 const int N=151;
14 int r[N],s[N],suf[N];
15 int64 f[2][N];
16 int main() {
17     const int n=getint(),a=getint(),b=getint();
18     for(register int i=0;i<n;i++) {
19         r[i]=getint(),s[i]=getint();
20     }
21     for(register int i=n-1;~i;i--) {
22         suf[i]=suf[i+1]+s[i];
23     }
24     for(register int i=0;i<=s[n-1];i++) {
25         f[!(n&1)][i]=-inf;
26     }
27     for(register int i=s[n-1]+1;i<=suf[0];i++) {
28         f[!(n&1)][i]=inf;
29     }
30     for(register int i=n-2;~i;i--) {
31         for(register int j=suf[i];~j;j--) {
32             if(s[i]>=j) {
33                 f[i&1][j]=-inf;
34                 while(j--) f[i&1][j]=-inf;
35                 break;
36             }
37             f[i&1][j]=-f[!(i&1)][suf[i]-j+1]-r[i]+1;
38             if(j<=suf[i+1]) {
39                 f[i&1][j]=std::min(f[i&1][j],std::max(1ll,f[!(i&1)][j]+r[i]+1));
40             }
41         }
42     }
43     for(register int i=suf[0];~i;i--) {
44         if(f[0][i]<=a-b) {
45             printf("%d %d
",i,suf[0]-i);
46             return 0;
47         }
48     }
49 }
原文地址:https://www.cnblogs.com/skylee03/p/7810232.html