传送门
这个题有趣。。。
巧妙地利用st表和堆
首先最暴力的我就不说了
第二个暴力就是主席树+堆,预计得分70~80,时间
O(klog2n)
std是用堆存储可能的区间,然后用st表查询区间最小值
因为其实如果知道区间右端点,再处理个前缀和s
那么就只要查询区间最小值就可以了,可以st表O(1)做
代码:
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#define mp(a,b,c,d) make_pair(make_pair(a,b),make_pair(c,d))
#define min(a,b) s[a]>s[b]?b:a
using namespace std;
inline int read(){
int x=0,f=1;char ch=0;
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
typedef pair<int,int> pii;
const int N=5e5+5;
int n,k,L,R;
int a[N],mn[19][N],Log[N],s[N];
long long ans=0;
priority_queue<pair<pii,pii> > q;
inline int query(int l,int r){
if(l>r)return -1;
int k=Log[r-l+1];
return min(mn[k][l],mn[k][r-(1<<k)+1]);
}
int main(){
n=read();k=read();L=read();R=read();Log[0]=-1;
for(int i=1;i<=n;++i)a[i]=read(),mn[0][i]=i,Log[i]=Log[i>>1]+1,s[i]=s[i-1]+a[i];
for(int k=1;k<=Log[n];++k)for(int i=0;i+(1<<k)-1<=n;++i)mn[k][i]=min(mn[k-1][i],mn[k-1][i+(1<<(k-1))]);
for(int i=L;i<=n;++i)q.push(mp(s[i]-s[query(max(0,i-R),i-L)],i,max(0,i-R),i-L));
int x,a,b,c,d,y;
for(int i=1;i<=k;++i){
pii p1=q.top().first,p2=q.top().second;
ans+=p1.first;x=p1.second;a=p2.first;b=p2.second;y=query(a,b);q.pop();
c=query(a,y-1);d=query(y+1,b);
if(c!=-1)q.push(mp(s[x]-s[c],x,a,y-1));
if(d!=-1)q.push(mp(s[x]-s[d],x,y+1,b));
}
printf("%lld",ans);
return 0;
}