题目:
题目链接:https://jzoj.net/senior/#main/show/4815
求一个数列前
k
k
k大的字段和。
思路:
由于
∑
i
=
k
n
a
[
i
]
<
∑
i
=
k
n
+
1
a
[
i
]
\sum_{i=k}^na[i]<\sum_{i=k}^{n+1}a[i]
∑i=kna[i]<∑i=kn+1a[i],所以我们直接建立一个大根堆,装对于每一个数
a
[
i
]
a[i]
a[i]的
s
u
m
(
i
∼
l
a
s
t
[
i
]
)
sum(i\sim last[i])
sum(i∼last[i]),其中
l
a
s
t
[
i
]
last[i]
last[i]初始均为
n
n
n。
然后从对顶弹出最大值,将
l
a
s
t
[
i
]
−
−
last[i]--
last[i]−−,再次插入。
时间复杂度
O
(
q
log
n
)
O(q\log n)
O(qlogn)
代码:
#include <queue>
#include <cstdio>
#include <algorithm>
#define mp make_pair
using namespace std;
typedef long long ll;
const int N=100010;
int n,m,last[N];
ll a[N],sum[N];
priority_queue<pair<ll,int> > q;
int main()
{
freopen("ksum.in","r",stdin);
freopen("ksum.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
sum[i]=sum[i-1]+a[i];
last[i]=n;
}
for (int i=1;i<=n;i++)
q.push(mp(sum[n]-sum[i-1],i));
while (m--)
{
printf("%lld ",q.top().first);
int pos=q.top().second;
q.pop();
if (last[pos]>pos)
{
last[pos]--;
q.push(mp(sum[last[pos]]-sum[pos-1],pos));
}
}
return 0;
}