问题描述
小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的音乐。
这架超级钢琴可以弹奏出n个音符,编号为1至n。第i个音符的美妙度为Ai,其中Ai可正可负。
一个“超级和弦”由若干个编号连续的音符组成,包含的音符个数不少于L且不多于R。我们定义超级和弦的美妙度为其包含的所有音符的美妙度之和。两个超级和弦被认为是相同的,当且仅当这两个超级和弦所包含的音符集合是相同的。
小Z决定创作一首由k个超级和弦组成的乐曲,为了使得乐曲更加动听,小Z要求该乐曲由k个不同的超级和弦组成。我们定义一首乐曲的美妙度为其所包含的所有超级和弦的美妙度之和。小Z想知道他能够创作出来的乐曲美妙度最大值是多少
输入格式
第一行包含四个正整数n, k, L, R。其中n为音符的个数,k为乐曲所包含的超级和弦个数,L和R分别是超级和弦所包含音符个数的下限和上限。
接下来n行,每行包含一个整数Ai,表示按编号从小到大每个音符的美妙度。
输出格式
只有一个整数,表示乐曲美妙度的最大值。
样例输入 1
4 3 2 3
3
2
-6
8
样例输出1
11
样例输入2
10 13 3 7
595
384
-435
-197
-677
661
4
-100
-653
220
样例输出2
1112
题解
即求前k 大连续区间和的和。
当k=1时,显然单调队列维护前缀和求解。
当k>1时,由于区间长度有限制,考虑快速查询以某个数为起点的第k 大连续区间和的方法。
求前缀和,问题变为求一段区间的第k 大前缀和。
即,对于第i 个数,以它为起点的第k 大连续区间和即为[ i+l-1,i+r-1 ]的第k 大前缀和减去第 i-1个数的前缀和。
考虑使用主席树。
下面求前k 大连续区间和。
假设现在讨论到求第x 大区间和。对于以第i 个数作为起点的区间和,只有之前未使用过的最大的区间和才可能是答案。
于是用堆。开始时把每个数为起点的最大连续区间和放入堆中,记录下值、起点位置,排名(开始时是1)。之后取k次,每次取完后将同一起点的次大的区间和放进堆内。
具体见代码。
代码
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
#define ll long long
using namespace std;
priority_queue<pair<ll ,pair<ll, ll > > > q;
const ll Q=40000000;
ll ls[Q],rs[Q],cnt[Q],n,k,a,b,d[500005],dis[500005],tot,maxr=500000,QAQ[500005];
void xiu(ll now,ll last,ll l,ll r,ll v)
{
cnt[now]=cnt[last]+1;
if(l==r)return;
ls[now]=ls[last];
rs[now]=rs[last];
ll mid=(l+r)>>1;
if(v<=mid)
ls[now]=++tot,xiu(ls[now],ls[last],l,mid,v);
else
rs[now]=++tot,xiu(rs[now],rs[last],mid+1,r,v);
}
void bt(ll now,ll l,ll r)
{
if(l==r)return;
ll mid=(l+r)>>1;
ls[now]=++tot,bt(tot,l,mid);
rs[now]=++tot,bt(tot,mid+1,r);
}
ll find(ll l,ll r,ll v)
{
while(l<=r)
{
ll mid=(l+r)>>1;
if(d[mid]>=v)r=mid-1;
else l=mid+1;
}
return l;
}
ll gr(ll nowl,ll nowr,ll l,ll r,ll v)
{
if(cnt[nowr]-cnt[nowl]<v)return -1;
if(l==r)return l;
ll mid=(l+r)>>1,lls=rs[nowl],rrs=rs[nowr];
if(cnt[rrs]-cnt[lls]>=v)return gr(lls,rrs,mid+1,r,v);
return gr(ls[nowl],ls[nowr],l,mid,v-(cnt[rrs]-cnt[lls]));
}
int main()
{
ll i,ans=0,ha,x,y,z;
scanf("%lld%lld%lld%lld",&n,&k,&a,&b);
tot=n;
for(i=1;i<=n;i++)
scanf("%lld",&x),QAQ[i]=d[i]=dis[i]=x+dis[i-1];
sort(d+1,d+n+1);
ha=unique(d+1,d+n+1)-(d+1);
bt(0,1,maxr);
for(i=1;i<=n;i++)
{
dis[i]=find(1,ha,dis[i]);
xiu(i,i-1,1,maxr,dis[i]);
}
for(i=1;i+a-1<=n;i++)
{
ha=gr(i+a-2,min(n,i+b-1),1,maxr,1);
q.push(make_pair(d[ha]-QAQ[i-1],make_pair(i,1)));
}
for(i=1;i<=k;i++)
{
x=q.top().first;
y=q.top().second.first;
z=q.top().second.second;
q.pop();
ans+=x;
ha=gr(y+a-2,min(n,y+b-1),1,maxr,z+1);
if(ha!=-1)q.push(make_pair(d[ha]-QAQ[y-1],make_pair(y,z+1)));
}
printf("%lld",ans);
return 0;
}