P2048题解+总结
主要思路
将[l , r]拆分成[l , pos - 1],[pos + 1 , r]分别弹入堆,弹出点pos
每次都选最优的子段,这样选 k 次。
另:struct 多元组函数写法如下点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 500005;
long long sum[MAXN],inrmq[MAXN][21],ans = 0;
void rmq_build(int n){
for(int i = 1;i <= n;i++){
inrmq[i][0] = i;
}
for(int j = 1;(1 << j) <= n;j++){
for(int i = 1;i + (1 << j) - 1 <= n;i++){
int xx = inrmq[i][j - 1];
int yy = inrmq[i + (1 << (j - 1))][j - 1];
inrmq[i][j] = sum[xx] > sum[yy] ? xx : yy;
}
}
}
int rmq_query(int l,int r){
int temp = log2(r - l + 1);
int x = inrmq[l][temp];
int y = inrmq[r - (1 << temp) + 1][temp];
return sum[x] > sum[y] ? x : y;
}
struct node{
int start,l,r,pos;
node(int x,int y,int z){
start = x;
l = y;
r = z;
pos = rmq_query(y,z);
}
friend bool operator < (const node& a,const node& b){
return sum[a.pos] - sum[a.start - 1] < sum[b.pos] - sum[b.start - 1];
}
};
priority_queue<node>q;
int main(){
freopen("1.out","r",stdin);
int n,k,leng,r;
cin >> n >> k >> leng >> r;
for(int i = 1;i <= n;i++){
cin >> sum[i];
sum[i] += sum[i - 1];
}
rmq_build(n);
for(int i = 1;i <= n;i++){
if(i + leng - 1 <= n){
node x=node(i,i + leng - 1,min(i + r - 1,n));
q.push(x);
//printf("%d %d %d %d\n",x.start,x.l,x.r,x.pos);
}
}
//printf("\n");
while(k--){
int tempst = q.top().start;
int templ = q.top().l;
int tempr = q.top().r;
int temppos = q.top().pos;
//printf("%d %d %d %d\n",tempst,templ,tempr,temppos);
q.pop();
ans += sum[temppos] - sum[tempst - 1];
if(templ != temppos) {
q.push(node(tempst,templ,temppos - 1));
}
if(tempr != temppos){
q.push(node(tempst,temppos + 1,tempr));
}
}
cout << ans;
return 0;
}