生日礼物(固定个数的连续区间最大值
Posted hhyx
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了生日礼物(固定个数的连续区间最大值相关的知识,希望对你有一定的参考价值。
# 题意
给定n个数,从中选不超过m个连续的部分使得它们的和最大
# 题解
输入过程直接把符号相同的区间合并为一个点,
计算出所有正数之和以及正数的个数cnt,如果cnt>m,
则需要挑选k=cnt-m处使区间变为m个,
两种操作都是在当前的和中减去一个值,
所以通过这样可以将正负操作归成一种操作
否则不需要做任何操作,和即最大值
将所有数的绝对值放在堆,每次选择最小的,
如果是正数,代表将当前的区间去掉,并和左右区间合并为一个
因为下次如果想要减少只能是两个正的合并
如果是负数,直接减去,代表和左右两遍的正数合并了,
负数的时候要判定左右,不能在区间的两端,因为如果负数绝对值最小且在两端点不能将两个正数区间合并,
也就是并没有实际减少,所以要特殊判断。
1 #include <bits/stdc++.h>
2 #define pii pair<int,int>
3 #define fi first
4 #define se second
5 using namespace std;
6 const int N=1e5+10;
7 int l[N],r[N];
8 priority_queue<pii,vector<pii>,greater<pii>>heap;
9 int a[N];
10 bool st[N];
11 void remove(int i){
12 r[l[i]]=r[i];
13 l[r[i]]=l[i];
14 st[i]=true;
15 }
16 int main(){
17 int n,m;
18 cin>>n>>m;
19 int k=1;
20 for(int i=0;i<n;i++){
21 int x;
22 cin>>x;
23 if((long long)x*a[k] < 0){
24 a[++k]=x;
25 }
26 else a[k]+=x;
27 }
28 n=k;
29
30 int cnt=0,sum=0;
31 for(int i=1;i<=n;i++) {
32 if (a[i] > 0) {
33 cnt++;
34 sum += a[i];
35 }
36 l[i]=i-1;
37 r[i]=i+1;
38 heap.push({abs(a[i]),i});
39 }
40
41 while(cnt>m){
42 while(st[heap.top().se]) heap.pop();
43
44 auto t=heap.top();
45 heap.pop();
46 int val=t.fi,idx=t.se;
47 if(l[idx]!=0 && r[idx]!=n+1 || a[idx]>0){//负数绝对值最小且在两端点不能将两个正数区间合并,也就是并没有实际减少,所以要特殊判断
48 cnt--;
49 sum-=val;
50 int left = l[idx],right=r[idx];
51 a[idx]+=a[left]+a[right];
52 heap.push({abs(a[idx]),idx});
53 remove(left);
54 remove(right);
55 }
56 }
57 cout<<sum<<endl;
58 }
以上是关于生日礼物(固定个数的连续区间最大值的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ3502/2288PA2012 Tanie linie/POJ Challenge生日礼物 堆+链表(模拟费用流)
BZOJ 2288 2288: POJ Challenge生日礼物 (贪心+优先队列+双向链表)