4815. 【NOIP2016提高A组五校联考4】ksum

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;
}
发布了199 篇原创文章 · 获赞 201 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/zsjzliziyang/article/details/103605498