生日礼物P10478

P10478 生日礼物

题目描述

ftiasch 18 岁生日的时候,lqp18_31 给她看了一个神奇的序列 \(A _ 1\), \(A _ 2\), ..., \(A _ N\)。 她被允许选择不超过 \(M\) 个连续的部分作为自己的生日礼物。

自然地,ftiasch 想要知道选择元素之和的最大值。你能帮助她吗?

输入格式

第 1 行,两个整数 \(N\) (\(1 \le N \le 10 ^ {5}\) ) 和 \(M\) (\(0 \le M \le 10 ^ 5\)),表示序列的长度和可以选择的部分。

第 2 行, \(N\) 个整数 \(A_1\), \(A_2\), ..., \(A_N\) (\(0 \le \mid A_i\mid \le 10^4\)),表示序列。

输出格式

一个整数,表示最大的和。

输入输出样例 #1

输入 #1

5 2
2 1 -2 3 -2

输出 #1

6

首先0不会产生任何影响,把所有连续的正数或者负数合并起来,因为如果正数是连续的肯定全部选上最优。
然后先把所有正数加进去,如果超过了m段,就维护一个优先队列把绝对值最小的取出来合并他两边的数成一段直到有m段

#include<bits/stdc++.h>
using namespace std;
int n,m,a[100005],cnt,k,l[100005],r[100005],f[100005],ans;
struct node{
	int data,id;
	bool operator <(const node &n)const{
		return abs(data)>abs(n.data);
	}
};
priority_queue<node> q;
bool check(int x) {return (0<l[x]&&r[x]<n+1)||a[x]>0;}
void del(int x){f[x]=1;l[r[x]]=l[x];r[l[x]]=r[x];}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		int x;cin>>x;if(x==0) continue;
		if(a[cnt]>0&&x>0||a[cnt]<0&&x<0) a[cnt]+=x;
		else a[++cnt]=x;
	}n=cnt;
	for(int i=1;i<=n;i++)
	{
		l[i]=i-1,r[i]=i+1;
		if(a[i]>0){k++;ans+=a[i];}
		q.push({a[i],i});
	}
	while(k>m)
	{
		if(q.empty()) break;
		int x=q.top().id;q.pop();
		if(f[x]) continue;
		if(check(x))
		{
			ans-=abs(a[x]);
			a[x]+=a[l[x]]+a[r[x]];
			del(l[x]),del(r[x]);
			q.push({a[x],x});
			k--;
		}
	}
	cout<<ans;
	return 0;
}```
posted @ 2025-10-10 17:30  cdqz_hfu_hzb  阅读(6)  评论(0)    收藏  举报