贪心LuoguP5653 基础最优化练习题 (我想不到的贪心
Posted kkkek
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了贪心LuoguP5653 基础最优化练习题 (我想不到的贪心相关的知识,希望对你有一定的参考价值。
题目大意:
一个x初值为0,每次可以给x加上值y,y∈[-k,k],同时必须保证第i次操作后 xi≤ai。需要进行n次操作。
有一个长度为n的序列 w,wi∈[-106,106]。
设第i次操作后x的值为bi,要求最大化Σni=1biwi。输出最大值。
数据范围:n≤106, −106≤wi?≤106, 0≤ai?≤108, 1≤k≤100。
做法:
y,w,a,b 所表示的 如题意。
Σni=1biwi = Σni=1biΣij=1yi = Σni=1yiΣnj=ibj
因为b是定值 所以 设ci=Σnj=ibj,即c是b的后缀和。
所以有:Σni=1biwi = Σni=1yici
设di=Σij=1bj,即 d是y的前缀和。
则 限制 是
对于所有di≤ai,对于所有y∈[-k,k]。
讲题人的题解是这么说的:
此时我们可以考虑根据c 贪心。
我们按照c 从大到小贪心,在能取的情况下尽量多取。
这样子贪心的正确性可以通过网络流建模来证明。由于建模部分较 为复杂这里不再展开。
所以,问题转化为,对于后缀和c,以c最大为最优,使c在不超“限制”的情况下取得对应y最大。
对我来说,这个贪心很难想。
知道这样子最优,做法也很难想。
结果删删改改 ,没有多少代码。只是 想无 (:3_ヽ)_
#include<bits/stdc++.h> #define debug printf("!"); using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; const int maxn=1e6+50; struct P{ ll w,lim; bool operator <(const P&p)const{return w>p.w;} }poi; ll a[maxn],b[maxn]; priority_queue<P>que; /* 从1到n 使得当前值取当前最优, 超过限制的值, 去找前i个值里小于 最优性低于当前值的最不优的可修改的值 减 无法修改的值就 吐出来 无法修改的值也 不要放进去 这样子 才能使 最大的尽可能最优 然后 这道题的贪心做法 要的就是使最大的值最优 */ int main() { int n; ll k,ans=0,sum=0,t,d,tt; scanf("%d%lld",&n,&k); for(int i=1;i<=n;i++)scanf("%lld",&a[i]); for(int i=1;i<=n;i++)scanf("%lld",&b[i]); for(int i=n-1;i>=1;i--)b[i]+=b[i+1]; for(int i=1;i<=n;i++) { if(b[i]<=0) { ans-=b[i]*k; sum-=k; t=sum-a[i]; if(t<=0)continue; d=0;//累积可以抵消的限制 while((!que.empty())&&d<t) { poi=que.top();que.pop(); tt=min(t-d,poi.lim); d+=tt; poi.lim-=tt; ans-=poi.w*tt; sum-=tt; if(poi.lim) { que.push(poi);break; } } continue; } if(que.empty()) { t=min(a[i]-sum,k); ans+=b[i]*t; sum+=t; que.push(P{b[i],t+k}); continue; } ans+=b[i]*k; sum+=k; que.push(P{b[i],k+k}); t=sum-a[i];//被限制 if(t<=0)continue; d=0;//累积可以抵消的限制 while((!que.empty())&&d<t) { poi=que.top();que.pop(); tt=min(t-d,poi.lim); d+=tt; poi.lim-=tt; ans-=poi.w*tt; sum-=tt; if(poi.lim) { que.push(poi);break; } } } printf("%lld ",ans); }
以上是关于贪心LuoguP5653 基础最优化练习题 (我想不到的贪心的主要内容,如果未能解决你的问题,请参考以下文章