Bzoj 2288 生日礼物题解

2288: 【POJ Challenge】生日礼物

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 856  Solved: 260
[Submit][Status][Discuss]

Description

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

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

Input

第1行,两个整数 N (1 ≤ N ≤ 105) 和 M (0 ≤ M ≤ 105), 序列的长度和可以选择的部分。

第2行, N 个整数 A1A2, ..., AN (0 ≤ |Ai| ≤ 104), 序列。

Output

一个整数,最大的和。

Sample Input

5 2

2 -3 2 -1 2

Sample Output

5

HINT

Source

  这道题当时第一眼以为连续的m个数,然后以为是二分加上单调队列,还好又读了一遍,发现是m个区间,这就比较有意思了,首先,我们可以先把所有符号相同的区间合在一起,来简化一下问题,然后这道题就变成了在一个正数与负数相间的数列中找出m个数使他们的和最大,但是我们要注意一点,这些数其实还可以合并成一个数,所以我们不能拿贪心去做。所以我们可以把答案分为两种情况,第一,所有正数的个数小于等于m那么我们可以直接输出了,第二正数的个数大于m,那么我们就有又有两种选择了,舍去某个正数或通过一个负数将两个区间合并在一起。对于位于首尾两个位置的负数我们可以的知他们并无法连接两个正数,换言之,选他们并不能减少当前所选的区间,所以我们在一开始就应当把他们刨去。同时我们也可以发现如果我们选了一个负数那么两侧的正数是不能再被选择丢掉的,而整个序列又是正负相间的,所以我们就可以将这个问题转化为在当前数列中选取若干个不相邻的数数是他们的和最小。然后,这道题就是Bzoj1150数据备份了。

  

 1 #include<iostream>
 2 #include<cstdlib>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<queue>
 6 #include<algorithm>
 7 #include<cmath>
 8 #include<map>
 9 #include<vector>
10 #define N 100005
11 using namespace std;
12 int n,m,a[N],zz;
13 struct no
14 {
15     long long sum;
16     int mid;
17     bool friend operator > (no a,no b)
18     {
19         return a.sum>b.sum;
20     }
21 }node[N];
22 int pre[N],fro[N];
23 bool fw[N];
24 priority_queue<no,vector<no>,greater<no > > q1;
25 int main()
26 {
27     scanf("%d%d",&n,&m);
28     for(int i=1;i<=n;i++)
29         scanf("%d",&a[i]);
30     long long sm=0,ans=0,js=0,la=0;
31     for(int i=1;i<=n;i++)
32     {
33         if(a[i]==0)continue;
34         if(a[i]*la<0)
35         {
36             zz++;
37             node[zz].sum=sm;
38             if(sm>0)
39             {
40                 js++;
41                 ans+=sm;
42             }
43             sm=0;
44             if(zz==1&&la<0)zz=0;
45         }
46         la=a[i];
47         sm+=a[i];
48     }
49     if(sm>0)
50     {
51         js++,ans+=sm;
52         zz++;
53         node[zz].sum=sm;
54     }
55     if(js<=m)
56     {
57         printf("%lld\n",ans);
58         exit(0);
59     }
60     m=js-m;
61     for(int i=1;i<=zz;i++)
62     {
63         node[i].mid=i;
64         node[i].sum=abs(node[i].sum);
65         q1.push(node[i]);
66         pre[i]=i-1,fro[i]=i+1;
67     }
68     fro[zz]=0;
69     node[0].sum=0x7fffffff;
70     while(m--)
71     {
72         while(fw[q1.top().mid]) q1.pop();
73         no tt=q1.top();q1.pop();
74         int x=tt.mid;
75         ans-=tt.sum;
76         tt.sum=-tt.sum;
77         tt.sum+=node[pre[x]].sum+node[fro[x]].sum;
78         node[x].sum=tt.sum;
79
80         fw[pre[x]]=fw[fro[x]]=1;
81         pre[x]=pre[pre[x]];
82         fro[x]=fro[fro[x]];
83         pre[fro[x]]=x;
84         fro[pre[x]]=x;
85         q1.push(tt);
86     }
87     printf("%lld\n",ans);
88     return 0;
89 }

时间: 2024-10-27 07:52:12

Bzoj 2288 生日礼物题解的相关文章

BZOJ 1179 Atm 题解

BZOJ 1179 Atm 题解 SPFA Algorithm Tarjan Algorithm Description Input 第一行包含两个整数N.M.N表示路口的个数,M表示道路条数.接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号.接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数.接下来一行包含两个整数S.P,S表示市中心的编号,也就是出发的路口.P表示酒吧数目.接下来的一行中有P个整数,表示P个有酒吧的路口

函数式trie思想 &amp; Bzoj 3261 &amp; 3166 题解

[原题1] 3261: 最大异或和 Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 497  Solved: 215 [Submit][Status] Description 给定一个非负整数序列 {a},初始长度为 N. 有   M个操作,有以下两种操作类型: 1 .A x:添加操作,表示在序列末尾添加一个数 x,序列的长度 N+1. 2 .Q l r x:询问操作,你需要找到一个位置 p,满足 l<=p<=r,使得: a[p] xor a[

BZOJ 1008 越狱 题解 裸快速幂

BZOJ 1008 越狱 题解 裸快速幂 1008: [HNOI2008]越狱 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 7887  Solved: 3372[Submit][Status][Discuss] Description 监狱有连续编号为1...N的N个房间,每个房间关押一个犯人,有M种宗教,每个犯人可能信仰其中一种.如果相邻房间的犯人的宗教相同,就可能发生越狱,求有多少种状态可能发生越狱 Input 输入两个整数M,N.1<=M<

[BZOJ 1179]ATM题解 Tarjan缩点+SPFA

[BZOJ 1179]ATM题解 Tarjan缩点+SPFA Description Input 第一行包含两个整数N.M.N表示路口的个数,M表示道路条数.接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号.接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数.接下来一行包含两个整数S.P,S表示市中心的编号,也就是出发的路口.P表示酒吧数目.接下来的一行中有P个整数,表示P个有酒吧的路口的编号 Output 输出一个整数,

斜率优化专题3——bzoj 3156 防御准备 题解

[原题] 3156: 防御准备 Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 198  Solved: 107 [Submit][Status] Description Input 第一行为一个整数N表示战线的总长度. 第二行N个整数,第i个整数表示在位置i放置守卫塔的花费Ai. Output 共一个整数,表示最小的战线花费值. Sample Input 10 2 3 1 5 4 5 6 3 1 2 Sample Output 18 HINT

bzoj 2506 calc 题解

[原题] 2506: calc Time Limit: 10 Sec  Memory Limit: 256 MB Submit: 228  Solved: 112 Description 给一个长度为n的非负整数序列A1,A2,-,An.现有m个询问,每次询问给出l,r,p,k,问满足l<=i<=r且Ai mod p = k的值i的个数. Input 第一行两个正整数n和m. 第二行n个数,表示A1,A2,-,An. 以下m行,每行四个数分别表示l,r,p,k.满足1<=l<=r&

BZOJ 2288 【POJ Challenge】生日礼物(贪心+优先队列)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2288 [题目大意] 给出一列数,求最多取m段连续的数字,使得总和最大 [题解] 首先我们对数据进行合并处理,连续的一段正数或者连续的一段负数处理成一个数字, 之后我们发现,如果正数的个数小于等于m,那么直接输出正数的总和即可, 如果大于m,我们有些正数不选,或者选择一些负数把左右两端的正数并起来. 这个负数的选择过程相当于减去这个数的绝对值, 正数选择拿出去的过程也相当于减去这个数的

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

2288: [POJ Challenge]生日礼物 Description ftiasch 18岁生日的时候,lqp18_31给她看了一个神奇的序列 A1, A2, ..., AN. 她被允许选择不超过 M 个连续的部分作为自己的生日礼物. 自然地,ftiasch想要知道选择元素之和的最大值.你能帮助她吗? Input 第1行,两个整数 N (1 ≤ N ≤ 105) 和 M (0 ≤ M ≤ 105), 序列的长度和可以选择的部分. 第2行, N 个整数 A1, A2, ..., AN (0

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

参考:http://blog.csdn.net/w_yqts/article/details/76037315 把相同符号的连续数字加起来,合并后ans先贪心的加上所有正数,如果正数个数sum>m,设计二元组(i,a[i])表示合并后序列i位置上值为a,记录前驱后继,塞进按绝对值排序的小根堆里.每次拿出来一个,减去这个x的a的绝对值,然后合并左右前驱后继,再塞回去. 如果拿出来的是正数,那么减去相当于原来选了现在不选,如果是负数,减去相当于选. 然后a值要改成a[l]+a[r]+a[x],下次再