Description
Input
Output
Sample Input
样例输入1:
3 4
1 3 4
样例输入2:
3 3
10 2 7
Sample Output
样例输出1:
8 7 4 4
样例输出2:
19 12 10
Data Constraint
Hint
Solution
题意:给你一个序列,让你求前大的子区间和。
很容易考虑到第一大的是[1,n],那么考虑第二大的是什么,一定是[1,n-1]和[2,n]中的一个。
因此,我们可以用堆维护区间,每次将堆顶弹出,再放入两个短1的两个小区间,再用哈希判一下重就好了。
这个是我考场的做法,但是我哈希打错了而丢了80分,这真是不应该。
其实还可以直接将所有[i,n]加进堆中,减的时候每次只用将对顶的右端点-1即可。
不论怎样堆中的元素个数一定是O(n)的。
时间复杂度O(k log n)。
第二种解法是维护前缀和后缀和
维护一前缀和后缀(子段=总和-前缀-后缀)
二分一个mid(前缀和后缀相互组合<=mid的总数>=k(两指针))使得mid最小,则总和-mid为最小的输出ans,接下就好办了。
时间o(nlog总和)。
Code1
#include<cstdio>
#include<cstring>
#include<algorithm>
#define I int
#define ll long long
#define F(i,a,b) for(I i=a;i<=b;i++)
#define Fd(i,a,b) for(I i=a;i>=b;i--)
#define mem(a,b) memset(a,b,sizeof(a))
#define N 1000010
#define M 190573
using namespace std;
I rd(I &x){
x=0;
char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
}
I n,k,x,y,tot=0;
ll a[N],h[N*2];
struct heap{I l,r;}d[N*2];
ll S(I x){return a[d[x].r]-a[d[x].l-1];}
void down(I x){
y=x<<1;
while(y<=tot&&S(y)>S(x)||y+1<=tot&&S(y+1)>S(x)){
y+=(y+1<=tot&&S(y+1)>S(y));
swap(d[x],d[y]);
x=y;y=x<<1;
}
}
void up(I x){
while(x>1&&S(x>>1)<S(x)){swap(d[x],d[x>>1]);x=x>>1;}
}
I hash(I x,I y){
ll t=(x*(ll)(N-10)+y);ll p=t%M;
while(h[p]&&h[p]!=t) p=(p+1)%M;
if(h[p]==t) return 1;
h[p]=t;
return 0;
}
void ins(I x,I y){
if(x>y||hash(x,y)) return;
d[++tot]=heap{x,y};
up(tot);
}
void del(I x){d[x]=d[tot--];down(x);}
I main(){
freopen("ksum.in","r",stdin);
freopen("ksum.out","w",stdout);
rd(n),rd(k);
F(i,1,n){rd(x);a[i]=a[i-1]+(ll)x;}
d[tot=1]=heap{1,n};
while(k--){
x=d[1].l,y=d[1].r;
printf("%lld ",S(1));
if(y>1) ins(x,y-1);
if(x<n) ins(x+1,y);
del(1);
}
return 0;
}
Code2
#pragma GCC optimize("Ofast")
%:pragma GCC optimize("inline")
#include<cstdio>
#include<algorithm>
#define I int
#define ll long long
#define F(i,a,b) for(I i=a;i<=b;i++)
#define Fd(i,a,b) for(I i=a;i>=b;i--)
#define N 1000010
using namespace std;
I n,m,k,a[N];
ll s[N],t[N],l,r,M,S,d[N];
I ck(ll x){
I j=1,T=0;
F(i,0,n-1){
if(s[i]>x) break;
while(j<=n+1&&s[i]+t[j]>x) j++;
T+=n-j+2;
}
return T;
}
I cmp(ll x,ll y){return x>y;}
I main(){
freopen("ksum.in","r",stdin);
freopen("ksum.out","w",stdout);
scanf("%d%d",&n,&k);
F(i,1,n){scanf("%d",&a[i]),r+=a[i],s[i]=s[i-1]+a[i];}
Fd(i,n,1) t[i]=t[i+1]+a[i];
while(l<=r){
M=l+r>>1;
if(ck(M)>=k) r=(S=M)-1;else l=M+1;
}
d[0]=0;
F(i,0,n-1){
Fd(j,n+1,1){
if(s[i]+t[j]>S) break;
d[++d[0]]=s[n]-s[i]-t[j];
}
}
sort(d+1,d+1+d[0],cmp);
F(i,1,k) printf("%lld ",d[i]);
return 0;
}