精力(power)

【问题描述】
假设你有一个属性叫”精力值”, 这个属性的上限为 E, 一开始你的精力值
为 E.每天结束时, 该属性会回复 R,但回复后不会超过上限 E。 现在有 N 天时
间给你去工作, 若第 i 天花费 K 的体力值去工作,那么你可以获得 V[i] * K 的
金钱。
问你这 N 天的最大收益是多少
【输入格式】
第一行一个整数 case,表示数据组数。
对于每一组数据, 第一行有三个整数 E, R, N, 第二行 N 个整数描述
V[1]~V[n]
【输出格式】
对于每组数据, 输出你的最大收益
【输入样例】
1
5 2 2
2 1
【输出样例】
12
【样例解释】
第一天用 5 体力, 接下来回复 2 点体力, 用光。

首先我们贪心,在越大的v是分配最多的体力

因为有体力回复的机制,所以不能一味分给最大的

考虑i-1和i,假设h[i]>h[i-1]

那么可以先将体力全部分给i-1,在把i-1的体力转给i

类似的用单调栈,维护一个单调递减的单调栈

设j=q[tail],且h[i]>h[j],j所用体力为rest[tail],i使用体力为p,显然p初始为R

则p+=min(m-p,rest[tail])

这里有个条件,p<m&&h[q[tail]]<h[i]

因为栈单调递减,所以尽量只把前面的且比h[i]小的体力转移,且总体力要<=m

q[tail]出栈代表体力已经转完了

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 using namespace std;
 6 int gi()
 7 {
 8   char ch=getchar();
 9   while (ch<'0'||ch>'9')ch=getchar();
10   int x=0;
11   while (ch>='0'&&ch<='9')
12     {
13       x=x*10+ch-'0';
14       ch=getchar();
15     }
16   return x;
17 }
18 long long s,r,n,a[500001],rest[500001],q[500001];
19 long long ans;
20 int main()
21 {int T,i,j,tail;
22   freopen("power.in","r",stdin);
23   freopen("power.out","w",stdout);
24   cin>>T;
25   while (T--)
26     {tail=0;
27       ans=0;
28       scanf("%lld%lld%lld",&s,&r,&n);
29       if (r>=s)
30     {
31       for (i=1;i<=n;i++)
32         a[i]=gi(),ans+=a[i]*s;
33       cout<<ans;
34     }
35       else
36      {
37       int p=s;
38       for (i=1;i<=n;i++)
39     {
40       a[i]=gi();
41       while (tail&&q[tail]<a[i]&&p<s)
42         {
43           int w=min(s-p,rest[tail]);
44             ans-=a[tail]*w;
45             p+=w;tail--;
46         }
47       tail++;
48       q[tail]=a[i];
49         ans+=a[i]*p;
50         rest[tail]=p;
51         p=r;
52     }
53       cout<<ans<<endl;
54       }
55     }
56 }

 

posted @ 2017-09-13 08:12  Z-Y-Y-S  阅读(509)  评论(0编辑  收藏  举报