题目

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

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

输入格式

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

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

输出格式

一个整数,最大的和。

输入样例

5 2

2 -3 2 -1 2

输出样例

5

题解

我们把连续的同号元素合并

得到的序列就是正负交错的序列

加入正数数量<=m,全部选掉就是答案

若正数数量>m,就对于某些数意味着

①不选该正数

②多选一个负数使得相邻正数相连,这样相当于可以少放弃一个正数

我们先将正数总和求出来

然后将所有数的绝对值加入小根堆

每次选出一个减去,然后与邻近的合并【就像选m个不相邻的数和最小一样】

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LL long long int
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
#define ls (u << 1)
#define rs (u << 1 | 1)
#define fa (u >> 1)
using namespace std;
const int maxn = 100005,maxm = 100005,INF = 1000000000;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
return out * flag;
}
int pre[maxn],nxt[maxn],val[maxn],n,m,A[maxn],V[maxn],tot,cnt;
struct node{int v,u;}H[2 * maxn];
int hsiz,pos[2 * maxn];
int pd(int u){
int small;
while (true){
small = u;
if (ls <= hsiz && H[ls].v < H[small].v) small = ls;
if (rs <= hsiz && H[rs].v < H[small].v) small = rs;
if (small != u){
pos[H[small].u] = u; pos[H[u].u] = small;
swap(H[small],H[u]);
u = small;
}else break;
}
return u;
}
void pup(int u){
while (u > 1 && H[fa].v > H[u].v){
pos[H[fa].u] = u; pos[H[u].u] = fa;
swap(H[fa],H[u]);
u = fa;
}
}
void ins(int u){
H[++hsiz] = (node){val[u],u}; pos[hsiz] = u;
pup(hsiz);
}
void del(int u){
pos[H[hsiz].u] = u;
swap(H[u],H[hsiz--]);
u = pd(u);
pup(u);
}
int main(){
n = read(); m = read();
REP(i,n){
A[++tot] = read();
if (!A[tot]) tot--;
}
int x = 1;
while (A[x] < 0 && x <= tot) x++;
if (x > tot) {puts("0"); return 0;}
V[n = 1] = A[x];
while (A[tot] < 0 && tot) tot--;
if (!tot) {puts("0"); return 0;}
for (int i = x + 1; i <= tot; i++){
if ((A[i] < 0 && A[i - 1] < 0) || (A[i] > 0 && A[i - 1] > 0))
V[n] += A[i];
else V[++n] = A[i];
}
cnt = n / 2 + 1;
if (cnt <= m){
sort(V + 1,V + 1 + n);
int ans = 0;
for (int i = 0; i < cnt && V[n - i] > 0; i++) ans += V[n - i];
printf("%d\n",ans);
}else {
int ans = 0;
for (int i = 1; i <= n; i++){
if (V[i] > 0) ans += V[i];
val[i] = abs(V[i]);
if (i > 1) pre[i] = i - 1;
if (i < n) nxt[i] = i + 1;
ins(i);
}
int t = cnt - m,x; node u;
while (t--){
u = H[1]; x = u.u;
ans -= u.v;
if (!pre[x]){
del(1); del(pos[nxt[x]]);
pre[nxt[nxt[x]]] = 0;
}else if (!nxt[x]){
del(1); del(pos[pre[x]]);
nxt[pre[pre[x]]] = 0;
}else {
int l = pre[x],r = nxt[x];
del(pos[l]); del(pos[r]);
H[1].v = val[x] = val[l] + val[r] - val[x]; pos[x] = 1;
pd(1);
nxt[pre[x] = pre[l]] = x;
pre[nxt[x] = nxt[r]] = x;
}
}
printf("%d\n",ans);
}
return 0;
}

BZOJ2288 【POJ Challenge】生日礼物 【堆 + 链表】的更多相关文章

  1. BZOJ3502PA2012Tanie linie&BZOJ2288[POJ Challenge]生日礼物——模拟费用流+链表+堆

    题目描述 n个数字,求不相交的总和最大的最多k个连续子序列. 1<= k<= N<= 1000000. 输入 输出 样例输入 5 2 7 -3 4 -9 5 样例输出 13   根据 ...

  2. [bzoj2288][POJ Challenge]生日礼物

    用堆维护双向链表来贪心... 数据范围显然不容许O(nm)的傻逼dp>_<..而且dp光是状态就n*m个了..显然没法优化 大概就会想到贪心乱搞了吧...一开始想贪心地通过几段小的负数把正 ...

  3. BZOJ 2288: 【POJ Challenge】生日礼物 堆&&链表

    就是堆+链表,十分像 数据备份 对吧? 把相邻的正数和相邻的负数合并成一整个正数块和负数块,最后只剩一些交替相间的正块与负块了吧? 显然,正块的个数<=m时,全部选走就获得了最大权值,否则我们可 ...

  4. 【BZOJ3502/2288】PA2012 Tanie linie/【POJ Challenge】生日礼物 堆+链表(模拟费用流)

    [BZOJ3502]PA2012 Tanie linie Description n个数字,求不相交的总和最大的最多k个连续子序列. 1<= k<= N<= 1000000. Sam ...

  5. BZOJ2288:[POJ Challenge]生日礼物——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=2288 ftiasch 18岁生日的时候,lqp18_31给她看了一个神奇的序列 A1, A2, . ...

  6. BZOJ2288:[POJ Challenge]生日礼物

    浅谈堆:https://www.cnblogs.com/AKMer/p/10284629.html 题目传送门:https://lydsy.com/JudgeOnline/problem.php?id ...

  7. [bzoj2288]【POJ Challenge】生日礼物_贪心_堆

    [POJ Challenge]生日礼物 题目大意:给定一个长度为$n$的序列,允许选择不超过$m$个连续的部分,求元素之和的最大值. 数据范围:$1\le n, m\le 10^5$. 题解: 显然的 ...

  8. 2288.【POJ Challenge】生日礼物 链表+堆+贪心

    BZOJ2288 [POJ Challenge]生日礼物 题意: 给一个长度为\(n\)的数组,最多可以选\(m\)个连续段,问选取的最大值是多少 题解: 先把连续的符号相同的值合并,头和尾的负数去掉 ...

  9. bzoj2288【POJ Challenge】生日礼物*

    bzoj2288[POJ Challenge]生日礼物 题意: 给一个序列,求不超过m个连续的部分,使元素和最大.序列大小≤100000 题解: 先把连续的正数和负数合并起来,接着如果正数个数小于m则 ...

  10. 【链表】BZOJ 2288: 【POJ Challenge】生日礼物

    2288: [POJ Challenge]生日礼物 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 382  Solved: 111[Submit][S ...

随机推荐

  1. 你知道现在的.net是什么样的吗,一张图告诉你

    Here are these concepts used in an example sentence, for context: Application Framework - “Are you u ...

  2. sql中保留2位小数

    问题: 数据库里的 float momey 类型,都会精确到多位小数.但有时候 我们不需要那么精确,例如,只精确到两位有效数字. 解决: 1. 使用 Round() 函数,如 Round(@num,2 ...

  3. Fixed table

    废话不多说,直接代码. <!DOCTYPE> <html> <head> <meta charset="utf-8"/> <s ...

  4. mohout安装

    安装完成之后的环境变量的配置如下: JAVA_HOME=/usr/local/jdk1.8.0_144JRE_HOME=/usr/java/jdk1.8.0_144/jreCLASSPATH=.:$J ...

  5. jni log 使用

    1. 在源文件中添加头文件 #include <android/log.h> #define LOG_TAG "System.out.c" #define LOGD(. ...

  6. OpenWrite方法打开现有文件并进行写入

    实现效果: 知识运用: File类的OpenWrite方法 //实现打开现有文件以进行写入 public static FileStream OpenWrite (string path) Encod ...

  7. SayLove微信小程序

    目录 SayLove 表白墙微信小程序 程序结构 说明 程序效果图 配置过程 结语 云开发 quickstart 参考文档 SayLove 表白墙微信小程序 项目地址:https://github.c ...

  8. 利用python进行数据分析2_数据采集与操作

    txt_filename = './files/python_baidu.txt' # 打开文件 file_obj = open(txt_filename, 'r', encoding='utf-8' ...

  9. php微信开发自动回复一直提示“该公众号提供的服务出现故障,请稍后再试”

    坑:服务器可以接受到发到公众号的信息,但是公众号不能回复,直接echo " ";exit();也会提示“该公众号提供的服务出现故障,请稍后再试”: 可能原因:用的php,是把数组转 ...

  10. ★房贷计算器 APP

    一.目的 1. 这是一个蛮有用的小工具 2. 之前看了很多demo,第一次来完全的自己实现一个APP 3. 完成之后提交 App Store 4. 作为Good Coder的提交审核材料 二.排期 周 ...