ABC281E Least Elements

本文介绍了解决ABC281E问题的方法,通过维护两个集合L和R来求解给定序列中特定子序列的前k小元素之和。使用multiset实现高效的插入和删除操作。

ABC281 E Least Elements

题目大意

给你一个长度为 n n n的序列 a a a,和整数 m m m k k k。对于每个 i = 1 , 2 , … n − m + 1 i=1,2,\dots n-m+1 i=1,2,nm+1,求出 a i , a i + 1 … a i + m − 1 a_i,a_i+1\dots a_{i+m-1} ai,ai+1ai+m1按升序排序后前 k k k个数的和。

令集合 L L L存储 a i , a i + 1 … a i + m − 1 a_i,a_{i+1}\dots a_{i+m-1} ai,ai+1ai+m1中前 k k k小的值,集合 R R R存储这 m m m个数中除了在 L L L中的值的其他的值。那么显然满足 max ⁡ L < min ⁡ R \max L<\min R maxL<minR,且此时 L L L中各元素之和就是当前的答案。

对于每一次 i i i的增加, a i a_i ai被删除, a i + m a_{i+m} ai+m被加入。我们可以做以下处理:

  • 确定 a i a_i ai在集合 L L L还是集合 R R R,删除 a i a_i ai
  • 如果 a i + m < max ⁡ L a_{i+m}<\max L ai+m<maxL,则放入集合 L L L;否则放入集合 R R R

此时 L L L满足 k − 1 ≤ ∣ L ∣ ≤ k + 1 k-1\leq|L|\leq k+1 k1Lk+1。我们要让 L L L的长度变为 k k k,则如果 ∣ L ∣ = = k − 1 |L|==k-1 L==k1,将 R R R中最小的元素放入 L L L中;如果 ∣ L ∣ = = k + 1 |L|==k+1 L==k+1,则将 L L L中最大的元素放入 R R R中。即可保证 L L L的长度始终为 k k k,即可求出当前答案。

m u l t i s e t multiset multiset可以使每次插入和删除操作为 O ( log ⁡ n ) O(\log n) O(logn),那么总时间复杂度为 O ( n log ⁡ n ) O(n\log n) O(nlogn)

code

#include<bits/stdc++.h>
using namespace std;
int n,m,k;
long long now=0,a[200005],ans[200005];
multiset<int>s;
int main()
{
	scanf("%d%d%d",&n,&m,&k);
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
	}
	for(int i=1;i<=m;i++){
		s.insert(a[i]);
	}
	multiset<int>::iterator it=s.begin();
	for(int i=1;i<=k;i++,it++) now+=*it;
	--it;
	for(int i=1;i<=n-m;i++){
		ans[i]=now;
		s.insert(a[i+m]);
		if(a[i+m]<*it){
			now=now-*it+a[i+m];--it;
		}
		if(a[i]<=*it){
			++it;now=now-a[i]+*it;
		}
		s.erase(a[i]);
	} 
	ans[n-m+1]=now;
	for(int i=1;i<=n-m+1;i++){
		printf("%lld ",ans[i]);
	}
	return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值