#贪心,KTT#CF573E Bear and Bowling
分析
考虑贪心,从空集开始每次选择增量最大的位置添加进集合,答案为每种大小集合的答案的最大值
增量与当前位置之前的选择数字个数以及之后的和有关,也就是 \(\Delta=a_i\cdot cnt+sum\) 是一次函数的形式。
每次添加完集合相当于把一段后缀的 cnt 加一,再把前缀加上 \(a_i\),同时把 \(i\) 所在位置的增量改成负无穷,那么前者用 KTT 实现后者直接打懒标记就可以了
代码
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long lll; const lll inf=1e18;
const int N=100011; int a[N],n; lll now,ans;
struct Segment_Tree{
lll K[N<<2],B[N<<2],P[N<<2],bound[N<<2],lazy[N<<2],lazy2[N<<2];
void pmax(lll k1,lll b1,int p1,lll k2,lll b2,int p2,lll &k,lll &b,lll &p,lll &bound){
if (b1<b2||(b1==b2&&k1<k2)) swap(k1,k2),swap(b1,b2),swap(p1,p2);
k=k1,b=b1,p=p1;
if (k1<k2) bound=min(bound,(b1-b2)/(k2-k1));
}
void pup(int k){
bound[k]=min(bound[k<<1],bound[k<<1|1]);
pmax(K[k<<1],B[k<<1],P[k<<1],K[k<<1|1],B[k<<1|1],P[k<<1|1],K[k],B[k],P[k],bound[k]);
}
void ptag(int k,lll z){
B[k]+=K[k]*z,lazy[k]+=z;
if (bound[k]!=inf) bound[k]-=z;
}
void build(int k,int l,int r){
lazy[k]=lazy2[k]=0;
if (l==r){
K[k]=a[l],B[k]=a[l],P[k]=l,bound[k]=inf;
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
pup(k);
}
void update(int k,int l,int r,int x,int y,lll z){
if (l==x&&r==y&&z<=bound[k]){
ptag(k,z);
return;
}
int mid=(l+r)>>1;
if (lazy[k]){
ptag(k<<1,lazy[k]);
ptag(k<<1|1,lazy[k]);
lazy[k]=0;
}
if (lazy2[k]){
B[k<<1]+=lazy2[k],lazy2[k<<1]+=lazy2[k],
B[k<<1|1]+=lazy2[k],lazy2[k<<1|1]+=lazy2[k],lazy2[k]=0;
}
if (y<=mid) update(k<<1,l,mid,x,y,z);
else if (x>mid) update(k<<1|1,mid+1,r,x,y,z);
else update(k<<1,l,mid,x,mid,z),update(k<<1|1,mid+1,r,mid+1,y,z);
pup(k);
}
void update2(int k,int l,int r,int x,int y,lll z){
if (l==x&&r==y){
B[k]+=z,lazy2[k]+=z;
return;
}
int mid=(l+r)>>1;
if (lazy[k]){
ptag(k<<1,lazy[k]);
ptag(k<<1|1,lazy[k]);
lazy[k]=0;
}
if (lazy2[k]){
B[k<<1]+=lazy2[k],lazy2[k<<1]+=lazy2[k],
B[k<<1|1]+=lazy2[k],lazy2[k<<1|1]+=lazy2[k],lazy2[k]=0;
}
if (y<=mid) update2(k<<1,l,mid,x,y,z);
else if (x>mid) update2(k<<1|1,mid+1,r,x,y,z);
else update2(k<<1,l,mid,x,mid,z),update2(k<<1|1,mid+1,r,mid+1,y,z);
pup(k);
}
}Tre;
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
for (int i=1;i<=n;++i) cin>>a[i];
Tre.build(1,1,n);
for (int i=1;i<=n;++i){
int t=Tre.P[1];
ans=max(ans,now+=Tre.B[1]);
Tre.update2(1,1,n,t,t,-inf);
if (t>1) Tre.update2(1,1,n,1,t-1,a[t]);
if (t<n) Tre.update(1,1,n,t+1,n,1);
}
cout<<ans;
return 0;
}

浙公网安备 33010602011771号