题目
长为n(n<=2e5)的两个序列a和b,第i个数分别ai(-1e9<=ai<=1e9),bi(-2e14<=bi<=2e14)
对于k从1到n,分别解决如下问题:
从[1,n]中选k个不同的位置,构成集合S,要求最大化,输出这个最大值
思路来源
uoj群qls
G题:https://qoj.ac/problem/7523
题解
主要是需要注意到决策单调性,注意到这个之后就比较好做了
考虑k=x的时候,已经在i处取到了[1,i]的最优决策,
那么当i变为i+1的时候,如果无脑选第i+1个位置,就构成了一种k=x+1的决策
当a[i+1]-a[rank[x](选的第x大的值)]-b[i+1]+b[i]>0的时候,能使k=x的决策更优
此时k=x的最优决策在i+1处取到,否则还是在第i处取到
反过来看,如果k=x+1的最优决策在j,
那么,k=x的最优决策要么在j(也就是通过满足上述加粗式,把之前最优决策里最小的a值扔掉)
要么在小于j的位置,也就是不满足加粗式,还是之前的决策方式
倘若k=x最优决策是在大于j的位置取到的,那么一定是将k=x在j处决策后的最优决策调的更优了,
把相同的调优手段应用给k=x+1,也能使k=x+1更优,与k=x+1的最优决策在j矛盾
综上,k=x决策点不大于k=x+1决策点
对于每个位置决策,主席树上维护一下当前的值有哪些,主要是需要查询topk大
分治一下,共查询O(nlogn)个位置的决策
代码
// Problem: G - Max (Sum - Max)
// Contest: AtCoder - Toyota Programming Contest 2024#4(AtCoder Beginner Contest 348)
// URL: https://atcoder.jp/contests/abc348/tasks/abc348_g
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
typedef long long ll;
typedef double db;
typedef pair<ll,int> P;
#define fi first
#define se second
#define pb push_back
#define dbg(x) cerr<<(#x)<<":"<<x<<" ";
#define dbg2(x) cerr<<(#x)<<":"<<x<<endl;
#define SZ(a) (int)(a.size())
#define sci(a) scanf("%d",&(a))
#define scll(a) scanf("%lld",&(a))
#define pt(a) printf("%d",a);
#define pte(a) printf("%d\n",a)
#define ptlle(a) printf("%lld\n",a)
#define debug(...) fprintf(stderr, __VA_ARGS__)
const int N=2e5+10,M=200*N;
const ll INF=1e18;
P d[N];
int n,a[N],m,x[N],tot;
int root[N],ls[M],rs[M],c;
ll b[N],sum[M],cnt[M],ans[N];
void upd(int l,int r,int &cur,int las,int pos,int v){
cur=++c;
ls[cur]=ls[las];rs[cur]=rs[las];
sum[cur]=sum[las]+v;
cnt[cur]=cnt[las]+1;
if(l==r){
return;
}
int mid=(l+r)/2;
if(pos<=mid)upd(l,mid,ls[cur],ls[las],pos,v);
else upd(mid+1,r,rs[cur],rs[las],pos,v);
}
ll ask(int cur,int l,int r,int k){
//printf("l:%d r:%d k:%d cnt:%d\n",l,r,k,cnt[cur]);
if(cnt[cur]<k)return -INF;
if(!cur)return 0;
if(l==r){
//printf("l:%d x:%d\n",l,x[l]);
return 1ll*k*x[l];
}
int mid=(l+r)/2,num=cnt[rs[cur]];
ll res=0;
if(num>=k)return ask(rs[cur],mid+1,r,k);
return sum[rs[cur]]+ask(ls[cur],l,mid,k-num);
}
ll cal(int p,int k){
ll w=ask(root[p],1,m,k)-d[p].fi;
//printf("p:%d k:%d dp.fi:%lld w:%lld\n",p,k,d[p].fi,w);
return w;
}
void dfs(int l,int r,int pl,int pr){
int mid=(l+r)/2,p=pl;
ll res=cal(pl,mid);
for(int j=pl+1;j<=pr;j++){
ll tmp=cal(j,mid);
if(tmp>res){
res=tmp;
p=j;
}
}
ans[mid]=res;
if(l<mid)dfs(l,mid-1,pl,p);
if(mid<r)dfs(mid+1,r,p,pr);
}
int main(){
sci(n);
rep(i,1,n){
scanf("%d%lld",&a[i],&b[i]);
x[i]=a[i];
d[i]=P(b[i],a[i]);
}
sort(x+1,x+n+1);
m=unique(x+1,x+n+1)-(x+1);
sort(d+1,d+n+1);
rep(i,1,n){
ll y=d[i].fi,z=d[i].se;
int p=lower_bound(x+1,x+m+1,z)-x;
root[i]=root[i-1];
//printf("i:%d p:%d z:%lld\n",i,p,z);
upd(1,m,root[i],root[i],p,z);
}
dfs(1,n,1,n);
rep(i,1,n){
printf("%lld\n",ans[i]);
}
return 0;
}