题目大意:
在整个区间里选k个长度在L-R之间的连续子段
求出最大答案
思路:
可以枚举区间的起点,然后可以查找长度合法的区间,从这段区间里找出来一个前缀和最大的然后减去起点
维护一个pq,每次弹出堆中最大的元素来,弹k次
堆里的每个元素记录这些信息:权值val,起点st,合法区间的l r,最大值的位置pos
找到堆顶,然后找到st为起点,对于[l,pos-1]和[pos+1,r]分别处理压入堆
贪心即可
因为需要找到区间一段和最大的 使用ST表
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<cstring> 6 #include<algorithm> 7 #include<vector> 8 #include<queue> 9 #define inf 2139062143 10 #define ll long long 11 #define MAXN 500100 12 using namespace std; 13 inline int read() 14 { 15 int x=0,f=1;char ch=getchar(); 16 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 17 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 18 return x*f; 19 } 20 int n,k,L,R,s[MAXN]; 21 ll ans; 22 struct data 23 { 24 int val,pos,l,r,st; 25 bool operator < (const data &a) const {return val<a.val;} 26 }f[MAXN][25]; 27 priority_queue <data> q; 28 data query(int l,int r) 29 { 30 int k=log2(r-l+1); 31 return (f[l][k].val>=f[r-(1<<k)+1][k].val)?f[l][k]:f[r-(1<<k)+1][k]; 32 } 33 void add(int l,int r,int st) 34 { 35 if(l>r) return; 36 data res=query(l,r); 37 res.val-=s[st-1],res.l=l,res.r=r,res.st=st; 38 q.push(res); 39 } 40 int main() 41 { 42 n=read(),k=read(),L=read(),R=read(); 43 for(int i=1;i<=n;i++) s[i]=s[i-1]+read(); 44 for(int i=1;i<=n;i++) f[i][0].val=s[i],f[i][0].pos=i; 45 for(int i=1;i<25;i++) 46 for(int j=1;j<=n;j++) 47 if(j+(1<<i)-1<=n) 48 if(f[j][i-1].val>=f[j+(1<<(i-1))][i-1].val) f[j][i]=f[j][i-1]; 49 else f[j][i]=f[j+(1<<(i-1))][i-1]; 50 for(int i=1;i<=n;i++) 51 { 52 if(i+L-1>n) break; 53 add(i+L-1,min(n,i+R-1),i); 54 } 55 while(k--) 56 { 57 data x=q.top();q.pop(); 58 ans+=(ll)x.val; 59 add(x.l,x.pos-1,x.st); 60 add(x.pos+1,x.r,x.st); 61 } 62 printf("%lld ",ans); 63 }