luoguP5653 基础最优化练习题 拆系数+贪心
直接算不好算,考虑拆开系数来算贡献.
对于 $b_{i}w_{i}$,可以看成 $1$ ~ $i$ 中每走一步就会产生 $w_{i}$ 的贡献,也就说 $i$ 的贡献就是 $i$ 的后缀和.
那么问题可以转化为:
有 $n$ 个元素,每个元素可以选 $[-k,k]$ 个,且第 $i$ 时刻选的元素个数不能超过 $a_{i}$.
显然,对于贡献为负数的肯定要全选,然后贡献为正的话先选上,然后再维护一个堆来删除即可.
code:
#include <queue>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define N 1000009
#define ll long long
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
ll sum[N];
int a[N],w[N];
struct data {
ll v;
int k;
data(ll v=0,int k=0):v(v),k(k){}
bool operator<(const data b) const {
return v>b.v;
}
};
priority_queue<data>q;
int main() {
// setIO("input");
int n,k;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
for(int i=1;i<=n;++i) scanf("%d",&w[i]);
for(int i=n;i>=1;--i) sum[i]=sum[i+1]+1ll*w[i];
ll mx=0;
ll cur=0;
for(int i=1;i<=n;++i) {
if(sum[i]<=0) {
mx-=1ll*k*sum[i];
cur-=1ll*k;
}
else {
mx+=1ll*k*sum[i];
cur+=1ll*k;
q.push(data(sum[i],k<<1));
}
while(cur>a[i]) {
data e=q.top(); q.pop();
if(cur-a[i]>e.k) {
mx-=1ll*e.k*e.v;
cur-=e.k;
}
else {
int det=cur-a[i];
mx-=1ll*det*e.v;
cur-=det;
if(e.k==det) break;
else q.push(data(e.v,e.k-det));
}
}
}
printf("%lld\n",mx);
return 0;
}

浙公网安备 33010602011771号