生日礼物(固定个数的连续区间最大值

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生日礼物 堆+链表(模拟费用流)

bzoj2288 POJ Challenge生日礼物

bzoj2288 生日礼物 (线段树)

BZOJ 2288 2288: POJ Challenge生日礼物 (贪心+优先队列+双向链表)

生日礼物 HYSBZ - 1293 单调队列求最短区间的长度,区间需要满足包含所有颜色种类

bzoj 2288: POJ Challenge生日礼物链表+堆