【题解】
先预处理出前缀和s[],问题转化为:求(s[j]-s[i])的前k大值之和 (0<=i<=n-L,L<=j-i<=R)
对于每一次求最值的过程:
若i相同,相当于求max(s[j])-s[i],属于RMQ问题
若i不同,存下每个i对应的max(s[j])-s[i],并存入大根堆
k次询问,每次都从堆顶弹出一个元素,计入答案,并将该元素对应的三元组(i,L,R)拆成两个:(i,L,Fr-1)与(i,Fr+1,R),重新求组内最大值并加入堆即可
其中的这个Fr作为j∈[i+L,i+R]时最大的(s[j]-s[i])对应j出现的位置到i的距离,在预处理RMQ问题用到的数组时一并记录即可
【代码】
#include<stdio.h>
#include<stdlib.h>
int d[500005][25]={0},from[500005][25]={0},s[500005]={0},start[2000005]={0},left[2000005]={0},right[2000005]={0};
int heap[1000005]={0},pos[1000005]={0};//大根堆相关
int p=0,node=0;
void jh(int* a,int* b)
{
int t=*a;
*a=*b;
*b=t;
}
int min(int a,int b)
{
if(a<b) return a;
return b;
}
int getmax(int L,int R)
{
int i=0;
while(L+(1<<i+1)<=R) i++;
if(d[L][i]>d[R-(1<<i)+1][i]) return d[L][i];
return d[R-(1<<i)+1][i];
}
int getfrom(int L,int R)
{
int i=0;
while(L+(1<<i+1)<=R) i++;
if(d[L][i]>d[R-(1<<i)+1][i]) return from[L][i];
return from[R-(1<<i)+1][i];
}
void tj(int x,int q)
{
int i;
heap[++node]=q;
pos[node]=x;
for(i=node;i>1;i/=2)
{
if(heap[i/2]<heap[i])
{
jh(&heap[i/2],&heap[i]);
jh(&pos[i/2],&pos[i]);
}
else return;
}
}
void sc()
{
int i=1;
jh(&heap[1],&heap[node]);
jh(&pos[1],&pos[node]);
node--;
while(i*2<=node)
{
i*=2;
if(i+1<=node&&heap[i]<heap[i+1]) i++;
if(heap[i/2]<heap[i])
{
jh(&heap[i/2],&heap[i]);
jh(&pos[i/2],&pos[i]);
}
else return;
}
}
int main()
{
long long ans=0;
int n,k,L,R,i,j,x,Fr;
scanf("%d%d%d%d",&n,&k,&L,&R);
for(i=1;i<=n;i++)
{
scanf("%d",&s[i]);
s[i]+=s[i-1];
d[i][0]=s[i];
from[i][0]=i;
}
for(i=1;(1<<i)<=n;i++)
for(j=1;j+(1<<i)-1<=n;j++)
{
if(d[j][i-1]>d[j+(1<<i-1)][i-1])
{
d[j][i]=d[j][i-1];
from[j][i]=from[j][i-1];
}
else
{
d[j][i]=d[j+(1<<i-1)][i-1];
from[j][i]=from[j+(1<<i-1)][i-1];
}
}
for(i=0;i<=n-L;i++)
{
start[++p]=i;
left[p]=i+L;
right[p]=min(i+R,n);
tj(p,getmax(left[p],right[p])-s[start[p]]);
}
for(;k>0;k--)
{
x=pos[1];
ans+=(long long)heap[1];
sc();
Fr=getfrom(left[x],right[x]);
if(left[x]<Fr)
{
start[++p]=start[x];
left[p]=left[x];
right[p]=Fr-1;
tj(p,getmax(left[p],right[p])-s[start[p]]);
}
if(right[x]>Fr)
{
start[++p]=start[x];
left[p]=Fr+1;
right[p]=right[x];
tj(p,getmax(left[p],right[p])-s[start[p]]);
}
}
printf("%lld",ans);
return 0;
}