首页 > 其他分享 >Least Prefix Sum

Least Prefix Sum

时间:2024-04-04 11:03:32浏览次数:21  
标签:le int Sum cdots tot Prefix erase Least multiset

题目链接

Hello 2023

C. Least Prefix Sum


思路:

仔细看式子,发现可以对它进行推理( m m m 是定值, 1 ≤ k ≤ n 1\le k\le n 1≤k≤n ):

  1. 当 k ≤ m k\le m k≤m 时,有 a 1 + a 2 + ⋯ + a k ≥ a 1 + a 2 + ⋯ + a m a_1 + a_2 + \cdots + a_k \geq a_1 + a_2 + \cdots + a_m a1​+a2​+⋯+ak​≥a1​+a2​+⋯+am​ 0 ≥ a k + 1 + a k + 2 + ⋯ + a m 0 \ge a_{k+1} + a_{k+2} + \cdots + a_m 0≥ak+1​+ak+2​+⋯+am​所以我们需要每个 [ k + 1 , m ] [k+1,m] [k+1,m] 区间的和都 ≤ 0 \le 0 ≤0, ( 1 ≤ k ≤ m ) (1\le k\le m) (1≤k≤m)。
  2. 当 k > m k\gt m k>m 时,有 a 1 + a 2 + ⋯ + a k ≥ a 1 + a 2 + ⋯ + a m a_1 + a_2 + \cdots + a_k \geq a_1 + a_2 + \cdots + a_m a1​+a2​+⋯+ak​≥a1​+a2​+⋯+am​ a m + 1 + a m + 2 + ⋯ + a n ≥ 0 a_{m+1} + a_{m+2} + \cdots + a_n \ge 0 am+1​+am+2​+⋯+an​≥0所以我们需要每个 [ m + 1 , n ] [m+1,n] [m+1,n] 区间的和都 ≥ 0 \ge 0 ≥0, ( 1 ≤ k ≤ m ) (1\le k\le m) (1≤k≤m)。

先看第一种情况,怎么用最小的操作次数维护这个性质呢?一种贪心的想法是从 m m m 向 2 2 2 看,如果满足条件就不动,如果不满足条件就选一个最大的数把它变成负的即可。这样跑一遍,操作的次数就是最少的。

怎么保证最大的数一定是正数,从而变负数呢?而且只操作一次即可呢?因为前面都满足条件,区间和为负数,到这个数就不满足条件了,所以这个数一定是正数,把它变负一定整个区间和都变成负数,我们去找更大的数变负,显然更满足条件。

第二种情况同理。这两种情况互不影响,所以贪心策略是正确的。维护最大值和最小值可以用优先队列或者 m u l t i s e t multiset multiset,不过 m u l t i s e t multiset multiset 使用 e r a s e erase erase 成员函数进行值的删除的时候,会把所有相同的值同时删除,所以要用 S . e r a s e ( S . f i n d ( x ) ) S.erase(S.find(x)) S.erase(S.find(x)) 的写法(迭代器删除)。

code:

#include <iostream>
#include <cstdio>
#include <set>
using namespace std;
const int maxn=2e5+5;
typedef long long ll;

int T,n,m,a[maxn];

int main(){
	cin>>T;
	while(T--){
		cin>>n>>m;
		for(int i=1;i<=n;i++)cin>>a[i];
		
		multiset<int> S;
		int cnt=0;
		ll tot=0;
		for(int i=m;i>=2;i--){
			S.insert(a[i]);
			tot+=a[i];
			if(tot>0){
				ll t=*S.rbegin();
				S.erase(S.find(t));
				tot-=t;
				
				t=-t;
				tot+=t;
				S.insert(t);
				
				cnt++;
			}
		}
		
		S.clear();
		tot=0;
		for(int i=m+1;i<=n;i++){
			S.insert(a[i]);
			tot+=a[i];
			if(tot<0){
				ll t=*S.begin();
				S.erase(S.begin());
				tot-=t;
				
				t=-t;
				tot+=t;
				S.insert(t);
				
				cnt++;
			}
		}
		cout<<cnt<<endl;
	}
	return 0;
}

标签:le,int,Sum,cdots,tot,Prefix,erase,Least,multiset
From: https://blog.csdn.net/qq_45809243/article/details/137369544

相关文章