题目
题意: 计算数组中所有长度为m的子段的前k小个数的和。
思路: 先计算前m个数,然后在此基础上动态增删。
如果k=m,直接减一个数加一个数就行了。
否则的话,拿mutliset维护。
对于删除的数x,如果x<=第k小,减去x,然后维护第k小的指针右移,再加上新的第k小这个数。
对于插入的数y,如果y<=第k小,减去第k小,指针左移,再加上新插入的数y。
可以画几个圈圈表示前k小的数,然后看看删除或者插入一个数应该怎么变动,维护好前k小就好了。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+10;
int n,m,k,T;
int a[N];
multiset<int> sa; //维护第k小
ll sum = 0;
void solve()
{
cin>>n>>m>>k;
for(int i=1;i<=n;++i) cin>>a[i];
for(int i=1;i<=m;++i) sa.insert(a[i]);
auto lst = sa.begin();
for(int cnt=k;cnt;--cnt,lst++)
{
sum += *lst;
}
lst--;
cout<<sum;
for(int i=1;i+m<=n;++i)
{
if(k==m)
{
sum -= a[i];
sum += a[i+m];
}
else
{
//删ai
if(a[i]<=*lst)
{
sum -= a[i];
lst++;
sum += *lst;
}
sa.erase(a[i]);
sa.insert(a[i+m]);
if(a[i+m]<=*lst)
{
sum -= *lst;
lst--;
sum += a[i+m];
}
}
cout<<" "<<sum;
}
}
signed main(void)
{
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
solve();
return 0;
}