子段的和 / 降序排序
题目链接:ybtoj高效进阶 21255 / ybtoj高效进阶 21267
题目大意
给你一个由非负数组成的数组,问你其中前 w 大的子区间和。
思路
由于是非负数,不难想到用堆解决。
(对于每个右起点先左端点为 1 1 1 放入堆中,然后每次取出当前最大的区间,然后右移它的左端点)
代码
#include<queue>
#include<cstdio>
#define ll long long
using namespace std;
int n, w, a[100001];
int to[100001];
priority_queue <pair<ll, int>, vector<pair<ll, int> >, less<pair<ll, int> > > q;
int main() {
// freopen("ksum.in", "r", stdin);
// freopen("ksum.out", "w", stdout);
// freopen("wsum.in", "r", stdin);
// freopen("wsum.out", "w", stdout);
scanf("%d %d", &n, &w);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]); to[i] = n;
}
ll now = 0;
for (int i = n; i >= 1; i--) {
now += 1ll * a[i];
q.push(make_pair(now, i));
}
for (int i = 1; i < w; i++) {
int now = q.top().second;
ll val = q.top().first;
printf("%lld ", val);
q.pop();
if (to[now] > now) {
val -= a[to[now]];
q.push(make_pair(val, now));
to[now]--;
}
}
printf("%lld", q.top().first);
return 0;
}