来补几发题解吧…从HN集训回来也做了几道题一直没发题解。
我们首先求出前缀和,然后枚举左端点
l
,右端点的所在范围就是
#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#define N 500005
using namespace std;
struct data
{
int i,l,r,t;
};
int n,K,L,R;
long long ans;
int a[N],f[N][20];
inline bool operator<(data x,data y)
{
return a[x.t]-a[x.i-1]<a[y.t]-a[y.i-1];
}
inline int query(int l,int r)
{
int k=log2(r-l+1);
int t1=f[l][k],t2=f[r-(1<<k)+1][k];
if (a[t1]>a[t2]) return t1;
else return t2;
}
inline void solve()
{
priority_queue<data> q;
for (int i=1;i<=n-L+1;i++)
{
int j=min(n,i+R-1);
q.push((data){i,i+L-1,j,query(i+L-1,j)});
}
for (int i=1;i<=K;i++)
{
data now=q.top(); q.pop();
ans+=a[now.t]-a[now.i-1];
if (now.t-1>=now.l) q.push((data){now.i,now.l,now.t-1,query(now.l,now.t-1)});
if (now.t+1<=now.r) q.push((data){now.i,now.t+1,now.r,query(now.t+1,now.r)});
}
}
int main()
{
scanf("%d%d%d%d",&n,&K,&L,&R);
for (int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
a[i]=a[i-1]+x;
}
for (int i=1;i<=n;i++)
f[i][0]=i;
for (int j=1;j<=18;j++)
for (int i=1;i<=n;i++)
if (i+(1<<j)-1<=n)
{
int t1=f[i][j-1],t2=f[i+(1<<(j-1))][j-1];
if (a[t1]<a[t2]) f[i][j]=t2;
else f[i][j]=t1;
}
solve();
cout << ans << endl;
}