精力(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 }