bzoj3502[PA2012]Tanie Linie(最大k区间和)
题意:给定一个长为n的数列,要求选出最多k个不相交的区间(可以不选),使得选中的数字之和最大.(1<=k<=n<=1000000)
分析:首先我们通过预处理对问题做一些简化.原序列中的0对答案没有影响,可以直接删掉.连续的一段正数或一段负数一定是都选或者都不选,可以合并成一个数字.这样把序列转化成了正数和负数交替出现的形式.如果序列的最左端/最右端是负数,这个负数在最优解当中一定不会被选中,我们可以把它删掉.这样就把序列变成了正负交替,以正数开头和结尾的形式.
这时若直接考虑选出k个不相交区间,仍然不好做.这里一个关键是先不考虑k的限制得到一个最优解,然后再对这个解进行调整使得它满足k的限制.
不考虑k的限制,最优解显然就是只选择所有正数,如果这时已经满足k的限制,就直接输出答案,否则我们需要进一步观察性质.
一开始,怎样修改这个解才能使得区间数目减少1呢?有两种方法:
1. 将某个正数由选中变为不选中,区间数减1
2. 将某个负数由不选中变为选中,可以连接两侧的区间使得区间数减1
显然,不论怎样操作,答案都会变小,这个变小的值就是我们修改状态的数的绝对值,那么第一步可以贪心的,现在的问题是怎样实现连续的贪心,并且每一步操作都让区间数减1.
考虑连续的三个数字… (左边一堆数)...a,b,c…(右边一堆数)…,不妨设a<0,c<0,b>0,如果b的权值最小,我们在第一步将b从选变成不选,那么之后单独将a或c从不选变成选就不能减少区间个数,我们打个标记将这两种决策删除掉.但这时有另外一种反悔的决策:同时选中abc三个数,这样可以让区间数再次减1.如果中间的数字是负数,也同理会使接下来可行的决策数目减少2,然后增加一种新的可行决策.我们用一个堆维护所有的决策(priority_queue足矣0),用一个链表维护每个位置前后第一个没有被删除的决策的位置,复杂度O(nlogn)
注意一个边界情况:a,b….(a的左边没有更多数字了,a>0,b<0),如果我们在选b之前将a从选中变为不选中,那么下一步同时选中ab将无法使区间数目减少(a的左边没有一个区间可以和右边连接),此时应当不添加新的决策.(这里我们在选中b之前选中了a,说明ab之和小于0,要么只选a,要么都不选,如果ab都选了一定没有都不选优).如果选a之前选中了b,这时将ab所在的区间变成都不选可以减少区间个数,不需要特殊处理.
类似于bzoj1150数据备份和bzoj2151种树.细节各种狗,一定要对拍…对拍可以费用流,也可以O(n^2)DP
#include<cstdio>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn=;
ll a[maxn];
bool del[maxn];
struct node{
ll w;int pos;
node(ll a,int b){
w=a;pos=b;
}
bool operator <(const node &B)const{
return w<B.w;
}
};
priority_queue<node> q;
int pre[maxn],nxt[maxn];ll val[maxn];
int main(){
int n,k;scanf("%d%d",&n,&k);
ll x;
int tot=;
scanf("%lld",&a[]);
for(int i=;i<=n;++i){
scanf("%lld",&x);//printf("%d\n",x);
if(x==)continue;
if((x>=)==(a[tot]>=)||a[tot]==)a[tot]+=x;
else a[++tot]=x;
}
ll sum=;int cnt=;
for(int i=;i<=tot;++i){
if(a[i]>=){//printf("%lld\n",a[i]);
sum+=a[i];cnt++;
}
}
if(cnt<=k){//printf("!");
printf("%lld\n",sum);
}else{
k=cnt-k;
int l=,r=tot;
if(a[]<)l++;
if(a[tot]<)r--;
if(tot==&&a[]<){
printf("0\n");
}else{
for(int i=l;i<r;++i)nxt[i]=i+;
for(int i=l+;i<=r;++i)pre[i]=i-;
for(int i=l;i<=r;++i)val[i]=(a[i]>=)?(-a[i]):a[i];
for(int i=l;i<=r;++i)q.push(node(val[i],i));
while(k--){//printf("!");
while(del[q.top().pos])q.pop();
node tmp=q.top();q.pop();
int i=tmp.pos;//printf("%d\n",tmp.w);
sum+=tmp.w;del[pre[i]]=del[nxt[i]]=true;
if(pre[i]&&nxt[i]){
val[i]=val[pre[i]]+val[nxt[i]]-val[i];
q.push(node(val[i],i));
pre[i]=pre[pre[i]];nxt[i]=nxt[nxt[i]];
if(nxt[i])pre[nxt[i]]=i;
if(pre[i])nxt[pre[i]]=i;
}else{
del[i]=true;pre[i]=pre[pre[i]];nxt[i]=nxt[nxt[i]];
if(nxt[i])pre[nxt[i]]=pre[i];
if(pre[i])nxt[pre[i]]=nxt[i];
}
}
}
printf("%lld\n",sum);
}
return ;
}
bzoj3502[PA2012]Tanie Linie(最大k区间和)的更多相关文章
- 【BZOJ3502/2288】PA2012 Tanie linie/【POJ Challenge】生日礼物 堆+链表(模拟费用流)
[BZOJ3502]PA2012 Tanie linie Description n个数字,求不相交的总和最大的最多k个连续子序列. 1<= k<= N<= 1000000. Sam ...
- 【BZOJ】3502 PA2012 Tanie linie
[算法]贪心,一般DP [题解] --- 胡策k≤10的环状DP做法: 1.钦定法:先确定第一位(可能和第n位)的状态,然后后面正常做DP,显然正确答案是一定会被记录的,因为从整体上看不会有影响. 2 ...
- 【BZOJ-3638&3272&3267&3502】k-Maximum Subsequence Sum 费用流构图 + 线段树手动增广
3638: Cf172 k-Maximum Subsequence Sum Time Limit: 50 Sec Memory Limit: 256 MBSubmit: 174 Solved: 9 ...
- bzoj AC倒序
Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...
- 主席树的各类模板(区间第k大数【动,静】,区间不同数的个数,区间<=k的个数)
取板粗 好东西来的 1.(HDOJ2665)http://acm.hdu.edu.cn/showproblem.php?pid=2665 (POJ2104)http://poj.org/probl ...
- Super Mario(线段树离线区间k值)
以前见过这题,没做出来,知道是离线处理,这次仔细想了下, 首先把出现的高度都map离散化一下,以离散化出来的数目g建树,把每个位置都开俩个vector,一个存以这个位置为L的询问,一个存以这个位置为R ...
- 蓝桥-区间K大数查询
问题描述: 给定一个序列,每次询问序列中第l个数到第r个数中第K大的数是哪个. 输入格式 第一行包含一个数n,表示序列长度. 第二行包含n个正整数,表示给定的序列. 第三个包含一个正整数m,表示询问个 ...
- 区间dp总结篇
前言:这两天没有写什么题目,把前两周做的有些意思的背包题和最长递增.公共子序列写了个总结.反过去写总结,总能让自己有一番收获......就区间dp来说,一开始我完全不明白它是怎么应用的,甚至于看解题报 ...
- 区间更新 zoj3911
哎,没什么坑点,一个简单的区间更新题,但是改了好几天没改对,最终还是过了~~发个纪念下 泪奔... #include<cstdio>#include <iostream>#in ...
随机推荐
- 汇编中resb这样的指令是什么意思?
转载下来,方便以后查看 原作网址:http://blog.csdn.net/m1j2t3/article/details/5681657 汇编中resb这样的指令是什么意思? 还有我在汇编程序中看到这 ...
- 鸡啄米:C++编程之十四学习之构造函数和析构函数
1. 本人学习鸡啄米课程的笔记记录,用来记录学习的历程和进度 2. 构造函数 我们在声明一个变量时,如果对它进行了初始化,那么在为此变量分配内存空间时还会向内存单元中写入变量的初始化.声明对象有相似的 ...
- spl_autoload_register()函数
一.__autoload 这是一个自动加载函数,在PHP5中,当我们实例化一个未定义的类时,就会触发此函数.看下面例子: printit.class.php <?php class PRINTI ...
- NPOI List数据源 导出excel
List数据源生成HSSFWorkbook通用方法: public class WorkBook { public static HSSFWorkbook BuildSwitchData<T&g ...
- P/Invoke 光标的操作
获取与设置光标在屏幕上的位置 GetCursorPos 获取光标在屏幕上的位置,光标位置始终是在屏幕坐标纵指定的,并且不受包含光标的窗口映射模式的影响 函数原型: BOOL GetCursorPos( ...
- Java开发工程师(Web方向) - 04.Spring框架 - 期末测试
Spring框架客观题 Spring框架编程题 http://blog.csdn.net/sinoacc/article/details/51702458 1 (25分) 假设有如下数据表: crea ...
- Java应用基础微专业-进阶篇
第1章--使用对象 1.1 字符类型 char c = 65; // char --> int char c = '\u0041'; // \u: unicode + (Hex 41--> ...
- JVM之G1收集器
Garbage-First,面向服务端的垃圾收集器. 并行与并发:充分利用多核环境减少停顿时间, 分代收集:不需要配合其它收集器 空间整合:整体上看属于标记整理算法,局部(region之间)数据复制算 ...
- Spring Boot下的lombok安装 (日志) 不能识别log变量问题
参考地址:http://blog.csdn.net/blueheart20/article/details/52909775 ps:除了要加载依赖之外 还要安装lombok插件
- 孤荷凌寒自学python第七十八天开始写Python的第一个爬虫8
孤荷凌寒自学python第七十八天开始写Python的第一个爬虫8 (完整学习过程屏幕记录视频地址在文末) 今天在上一天的基础上继续完成对我的第一个代码程序的书写. 到今天止基本完成了对docx模块针 ...