传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1024

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1053

【题解】

原来的解法:http://www.cnblogs.com/galaxies/p/hdu1024.html

原来的解法思路是正着,我们加数,现在考虑删数

我们先特判几种情况(可以全选正,全选正还不够)

现在只剩下一种情况,段数<正数段数

我们可以把数字合并变成+/-/+/-...这个情况

那我们考虑的是合并。

每次我们选出+的段,意为舍弃这一段

选出-的段,意为把这一段和旁边两个正段合并

所以选出代表要把这段绝对值从答案里减去,我们希望越小越好,所以维护一个小根堆(或set)

那么合并的时候把选出的段和旁边两段直接相加即可,由于这个绝对值是最小的,所以加起来还是旁边两段的符号。

特别注意如果在边界上出现了负数那么这个负数是没有任何用的,因为我们选他不能合并来使段数减小,所以直接删掉即可。

进队列的时候如果边界上出现了0,那么一样把它删掉,因为选0一定是出现这种情况

10000 -10000 -10000 ....

然后你选了第一个,变成了0 -10000 ...

很明显我们第一次选了10000,意为舍弃它,并合并,所以和周围合并变成了0,再选0,没有任何意义,不能使段数减小,反而增加。

至于为什么不能在取top的时候判,因为会有这种情况

m=1,n=4,a[]={0,-1,-1,0}

原本是0,就已经合法,是有实际意义的,所以不能判掉。

然后就过了

# include <set>
# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm>
// # include <bits/stdc++.h> using namespace std; typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int M = 1e6 + ;
const int mod = 1e9+; # define RG register
# define ST static ll a[M], ans = ;
int m, n;
int p[M], pn;
int tot1, tot2;
set< pair<ll, int> > s; inline int sgn(int x) {return x<?:;}
inline ll myabs(ll x) {return x>?x:-x;} inline void transform() {
n = ;
ll t = p[]; int s = sgn(t);
for (int i=; i<=pn; ++i) {
if(sgn(p[i]) == s)
t += p[i];
else {
a[++n] = t;
t = p[i];
s = sgn(t);
}
}
a[++n] = t;
// for (int i=1; i<=n; ++i) printf("%d ", a[i]);
} int Minus[M];
inline void solve_minus() {
int tn = , tem = m-tot1;
for (int i=; i<=pn; ++i) if(p[i] < ) Minus[++tn] = p[i];
sort(Minus+, Minus+tn+);
while(tem--) ans += Minus[tn--];
} int L[M], R[M]; inline void del(int x) {
L[R[x]] = L[x];
R[L[x]] = R[x];
} inline void solve() {
s.clear();
int T = tot2 - m;
for (int i=; i<=n+; ++i) L[i] = R[i] = ;
for (int i=; i<n; ++i) L[i] = i-, R[i] = i+;
L[n] = n-;
for (int i=; i<=n; ++i) s.insert(make_pair(myabs(a[i]), i));
// cout << T << endl;
while(T--) {
pair<ll, int> top = *s.begin();
s.erase(top);
int x = top.second, y;
if(a[x] < && (!L[x] || !R[x])) {
del(x);
++T;
continue;
}
ll sum = a[x];
ans -= myabs(sum);
if(L[x]) {
y = L[x];
sum += a[y];
s.erase(make_pair(myabs(a[y]), y));
del(L[x]);
}
if(R[x]) {
y = R[x];
sum += a[y];
s.erase(make_pair(myabs(a[y]), y));
del(R[x]);
}
a[x] = sum;
if(sum == ) del(x);
else s.insert(make_pair(myabs(a[x]), x));
}
} int main() {
while(cin >> m >> pn) {
tot1 = tot2 = ;
for (int i=; i<=pn; ++i) scanf("%d", p+i);
transform();
for (int i=; i<=pn; ++i) tot1 += (p[i] >= );
for (int i=; i<=n; ++i) tot2 += (a[i] >= );
ans = ;
for (int i=; i<=n; ++i)
if(a[i] >= ) ans += a[i];
// for (int i=1; i<=n; ++i) cout << a[i] << ' ';
// cout << endl;
// cout << "ans = " << ans << endl;
if(tot2 <= m && m <= tot1) cout << ans << endl;
else if(m > tot1) {
solve_minus();
cout << ans << endl;
} else {
solve();
cout << ans << endl;
}
}
return ;
}

最新文章

  1. .net framework 3.5sp1 安装不成功
  2. Gvr SDK for Unity 分析(一)
  3. HDU 2855 (矩阵快速幂)
  4. 读《java核心技术卷一》有感
  5. 一个不错的java的配置文件的设置
  6. 站长、运维必备| 网站可用性监控产品 OneAPM Cloud Test 上线
  7. 【Demo 0016】SQLite 数据库
  8. PHP接收android传过来的图片
  9. Jenkins结合.net平台工具之Opencover
  10. selenium + firefox驱动版本对应。
  11. 使ipconfig命令结果更整洁
  12. HDU 5754 Life Winner Bo(各类博弈大杂合)
  13. 2017php经典面试题
  14. [c/c++]指针(3)
  15. C# Arc Gis实例教程——网络链接
  16. 使用POI设置导出的EXCEL锁定指定的单元格
  17. Swing与AWT在事件模型处理上是一致的
  18. Shell 命令行实现将一个站点页面全部下载到本地并替换其中链接的脚本
  19. 【推荐】CentOS安装vsftpd-3.0.3+安全配置
  20. Struts2工作原理和执行流程图

热门文章

  1. 以CentOS为操作系统的vps或服务器安装lnmp运行环境的方法
  2. 微信小程序本地缓存
  3. 基于pandas进行数据预处理
  4. PAT Basic 1057
  5. SAP(ABAP):STOP,EXIT,CHECK,RETURN,REJECT,CONTINUE
  6. 笔记-scrapy-深入学习-sheduler
  7. X的N次方。N比较大。
  8. js模板引擎之 Handlebars 基本用法
  9. USACO Section2.3 Longest Prefix 解题报告 【icedream61】
  10. python学习笔记十七:base64及md5编码