给出 nnn 个数AiA_iAi,
定义排列一个 111~nnn 的排列 PPP 的价值为:
∑i≤nAi∗Pi\sum_{i\le n}A_i*P_i∑i≤nAi∗Pi
请你给出排列价值前 kkk 小的 kkk 个排列的价值。
n,k≤1e5n,k\le1e5n,k≤1e5
考虑k=1k=1k=1时
我们就是求一个排列得到∑i=1nApi∗(n−i+1)\sum_{i=1}^{n}A_{p_i}*(n-i+1)∑i=1nApi∗(n−i+1)最小
显然AAA升序最小
现在考虑ppp不动,每次改变AAA
现在考虑我们如何从前kkk小解拓展到k+1k+1k+1小
考虑每次选择一段区间[v,u][v,u][v,u],将Av=Av,AvA_v=A_v,A_{v}Av=Av,Av ~Au+1A_{u+1}Au+1依次像右移一位
显然一次的增量是∑l=1u−vAu−Au−l\sum_{l=1}^{u-v}A_{_u}-A_{_{u-l}}∑l=1u−vAu−Au−l
显然所有解一定是这样拓展得到的
考虑对于一个pospospos维护一个lll使得pospospos向左拓展lll位增量最小
记g(pos,l)g(pos,l)g(pos,l)表示pospospos往左拓展lll位的增量
那么有g(pos,l)≤g(pos,l+1)g(pos,l)\le g(pos,l+1)g(pos,l)≤g(pos,l+1)
那么每次我们就对于∑i=1n\sum_{i=1}^{n}∑i=1n维护一个Max(g(pos,lpos))Max(g(pos,l_{pos}))Max(g(pos,lpos))
考虑用一个主席树维护一下没有用过的AAA
每一次拓展,也就是把AAA循环位移一段[l,r][l,r][l,r]
就相当于删去[1,l−1][1,l-1][1,l−1],并把这段加到rrr后面
我们发现这样操作每次的ggg和lll都可以直接维护(雾)
用个堆维护一下最小值就完了
#include<bits/stdc++.h>
using namespace std;
#define gc getchar
inline int read(){
char ch=gc();
int res=0,f=1;
while(!isdigit(ch))f^=ch=='-',ch=gc();
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
return f?res:-res;
}
#define re register
#define pii pair<ll,int>
#define pb push_back
#define fi first
#define se second
#define cs const
#define ll long long
const int N=100005;
const ll inf=1e18;
int n,a[N];
namespace Seg{
#define M N*101
#define mid ((l+r)>>1)
int tt;
struct node{
int pos,len,siz,lc,rc;ll mx;
}tr[M];
#define lc tr[u].lc
#define rc tr[u].rc
inline void build(int &u,int l,int r){
u=++tt,tr[u].siz=r-l+1;
if(l==r)return;
build(lc,l,mid),build(rc,mid+1,r);
}
inline void pushup(int u){
if(tr[lc].mx<tr[rc].mx)tr[u].pos=tr[lc].pos,tr[u].len=tr[lc].len,tr[u].mx=tr[lc].mx;
else tr[u].pos=tr[lc].siz+tr[rc].pos,tr[u].len=tr[rc].len,tr[u].mx=tr[rc].mx;
tr[u].siz=tr[lc].siz+tr[rc].siz;
}
inline void insert(int l,int r,int &r1,int k,ll mx){
int u=++tt;tr[u]=tr[r1],r1=u;
if(!lc&&!rc){
tr[u].len++,tr[u].pos=tr[u].siz=1,tr[u].mx+=mx;
return;
}
if(tr[lc].siz>=k)insert(l,mid,lc,k,mx);
else insert(mid+1,r,rc,k-tr[lc].siz,mx);
pushup(u);
}
inline void update(int &r1,int k,ll mx,int siz){
int u=++tt;tr[u]=tr[r1],r1=u;
if(!lc&&!rc){
tr[u].pos=tr[u].siz=siz,tr[u].mx=mx;return;
}
if(tr[lc].siz>=k)update(lc,k,mx,siz);
else update(rc,k-tr[lc].siz,mx,siz);
pushup(u);
}
inline void delet(int &r1,int k){
if(!k)return;
int u=++tt;tr[u]=tr[r1],r1=u;
if(tr[lc].siz>k)delet(lc,k);
else k-=tr[lc].siz,lc=0,delet(rc,k);
pushup(u);
}
inline int query(int u,int l,int r,int k){
if(l==r)return a[l];
if(tr[lc].siz>=k)return query(lc,l,mid,k);
return query(rc,mid+1,r,k-tr[lc].siz);
}
}
using namespace Seg;
struct data{
int rt,nxt;ll mx;
}p[N];
int tot;
priority_queue<pii,vector<pii>,greater<pii> > q;
inline void calc(int pre){
int u=p[pre].rt;
p[++tot].mx=p[pre].mx+tr[u].mx;
p[tot].rt=p[pre].nxt;
int pos=tr[u].pos,len=tr[u].len,last=pos-len;
update(p[tot].rt,pos,inf,0);
if(last>1)delet(p[tot].rt,last-1);
if(len<tr[p[tot].rt].siz)update(p[tot].rt,len+1,query(p[tot].rt,1,n,len+1)-query(p[tot].rt,1,n,len),1);
update(p[tot].rt,1,inf,1);
p[tot].nxt=p[tot].rt;
q.push(pii(p[tot].mx+tr[p[tot].rt].mx,tot));
if(pos>len+1)insert(1,n,p[pre].rt,pos,query(p[pre].rt,1,n,pos)-query(p[pre].rt,1,n,pos-len-1));
else insert(1,n,p[pre].rt,pos,inf);
q.push(pii(p[pre].mx+tr[p[pre].rt].mx,pre));
}
signed main(){
#ifdef Stargazer
freopen("lx.cpp","r",stdin);
#endif
n=read();int k=read();
for(int i=1;i<=n;i++)a[i]=read();
sort(a+1,a+n+1);
tr[0].mx=inf,build(p[0].rt,1,n);
for(int i=1;i<=n;i++){
p[0].mx+=1ll*a[i]*(n-i+1);
if(i>1)insert(1,n,p[0].rt,i,a[i]-a[i-1]);
else insert(1,n,p[0].rt,i,inf);
}
p[0].nxt=p[0].rt;
cout<<p[0].mx<<'\n';
q.push(pii(p[0].mx+tr[p[0].rt].mx,0));
for(int i=1;i<k;i++){
pii now=q.top();q.pop();
cout<<now.fi<<'\n';
calc(now.se);
}
}