直接算不好算,考虑拆开系数来算贡献.
对于 $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 ",mx); return 0; }