51nod 最大M子段和系列
第1行:2个数N和M,中间用空格分隔。N为整数的个数,M为划分为多少段。(2 <= N , M <= 5000)
第2 - N+1行:N个整数 (-10^9 <= a[i] <= 10^9)
输出这个最大和
7 2
-2
11
-4
13
-5
6
-2
26
———————————————————————————————————
1254 最大子段和 V2
第1行:整数序列的长度N(2 <= N <= 50000)
第2 - N + 1行:N个整数(-10^9 <= A[i] <= 10^9)
输出交换一次后的最大子段和。
7
-2
11
-4
13
-5
-2
4
28
——————————————————————————
因为这两道题是一种写法所以我就写在一起
就把连续的一段正负的合在一起得到一段正负相间的序列
然后记录一共有多少个正的记为tot 题目要保留的段数记为 k
那么我们就需要消掉tot-k份 消掉的方法有放弃某一段正的或者是用一段负的把两段正的合并
这样我们维护一个堆 权值是需要付出的代价 这样慢慢合并就能解决问题了
记得记录每一段的相邻段就好辣 当然记得特判边界 我的处理方法是加一段权值为负无穷的段就好辣
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define LL long long
using namespace std;
const int M=1e6+1e5+;
const LL inf=1e15;
LL read(){
LL ans=,f=,c=getchar();
while(c<''||c>''){if(c=='-') f=-; c=getchar();}
while(c>=''&&c<=''){ans=ans*+(c-''); c=getchar();}
return ans*f;
}
int n,k,f[M],lx[M],rx[M];
LL cnt,sum[M],v,ans;
bool pd(LL x,LL y){return !x||!y||(x>)==(y>);}
LL pabs(LL x){return x>=?x:-x;}
struct node{
LL w,pos;
bool operator <(const node& x)const{return x.w<w;}
};
priority_queue<node>q;
int main(){
n=read(); k=read();
int h=;
while(h<=n&&(v=read())<=) h++;//printf("[%d]\n",h);
if(v>) sum[++cnt]=v;
for(int i=h+;i<=n;i++){
v=read();
if(pd(sum[cnt],v)) sum[cnt]+=v;
else sum[++cnt]=v;
}
if(pd(sum[cnt],-inf)) sum[cnt]+=-inf;
else sum[++cnt]=-inf;
int tot=; for(int i=;i<=cnt;i++)if(sum[i]>=) ans+=sum[i],tot++;
if(tot<=k) return printf("%lld\n",ans),;
int now=tot-k;
for(int i=;i<=cnt;i++) q.push((node){pabs(sum[i]),i}),lx[i]=i-,rx[i]=i+;
lx[]=cnt; rx[cnt]=;
while(now){
node x=q.top(); q.pop();
int k=x.pos;
if(f[k]) continue;
ans-=x.w; now--;
LL l=lx[k],r=rx[k];
f[l]=; f[r]=;
sum[++cnt]=sum[k]+sum[l]+sum[r];
q.push((node){pabs(sum[cnt]),cnt});
lx[cnt]=lx[l]; rx[cnt]=rx[r];
rx[lx[l]]=cnt; lx[rx[r]]=cnt;
}
printf("%lld\n",ans);
return ;
}
第1行:2个数N和M,中间用空格分隔。N为整数的个数,M为划分为多少段。(2 <= N , M <= 100000)
第2 - N+1行:N个整数 (-10^9 <= a[i] <= 10^9)
输出这个最大和
7 2
-2
11
-4
13
-5
6
-2
26
————————————————————————
这道题不需要特判边界反而更容易QAQ
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
#include<cstdlib>
#define LL long long
using namespace std;
const int M=;
LL read(){
LL ans=,f=,c=getchar();
while(c<''||c>''){if(c=='-') f=-; c=getchar();}
while(c>=''&&c<=''){ans=ans*+(c-''); c=getchar();}
return ans*f;
}
LL lx[M],rx[M],w[M];
LL n,k,tot;
LL cnt=;
LL sum[M],ans;
bool f[M];
struct node{
LL w,pos;
bool operator<(const node &x) const{return w>x.w;}
};
priority_queue<node>q;
LL pd(LL x){return x>=?x:-x;}
bool okay(LL a,LL b){return (a<&&b<)||(a>&&b>)||!a||!b;}
int main()
{
LL v;
n=read(); k=read();
for(int i=;i<=n;i++){
v=read();
if(okay(sum[cnt],v)) sum[cnt]+=v;
else sum[++cnt]=v;
}
if(okay(sum[],sum[cnt])) sum[]=sum[cnt]+sum[],cnt--;
for(int i=;i<=cnt;i++)
if(sum[i]>) ans+=sum[i],tot++;
if(tot<=k){printf("%lld\n",ans); return ;}
LL now=tot-k;
q.push((node){pd(sum[]),});
lx[]=cnt; rx[]=; w[]=pd(sum[]);
q.push((node){pd(sum[cnt]),cnt});
lx[cnt]=cnt-; rx[cnt]=; w[cnt]=pd(sum[cnt]);
for(int i=;i<cnt;i++)
q.push((node){pd(sum[i]),i}),lx[i]=i-,rx[i]=i+,w[i]=pd(sum[i]);
while(now){
node x=q.top(); q.pop();
LL k=x.pos;
if(f[k]) continue;
ans-=w[k]; now--;
LL l=lx[k],r=rx[k];
f[l]=; f[r]=;
cnt++;
sum[cnt]=sum[k]+sum[l]+sum[r];
w[cnt]=pd(sum[cnt]);
q.push((node){w[cnt],cnt});
lx[cnt]=lx[l]; rx[cnt]=rx[r];
rx[lx[l]]=cnt; lx[rx[r]]=cnt;
}
printf("%lld\n",ans);
return ;
}
51nod 最大M子段和系列的更多相关文章
- 51Nod 最大M子段和系列 V1 V2 V3
前言 \(HE\)沾\(BJ\)的光成功滚回家里了...这堆最大子段和的题抠了半天,然而各位\(dalao\)们都已经去做概率了...先%为敬. 引流之主:老姚的博客 最大M子段和 V1 思路 最简单 ...
- 51nod 最大M子段和系列(1052、1053、1115)
51nod1052 数据量小,可使用O(N*M)的DPAC,递推公式: dp[i][j]=max(dp[i-1][j-1], dp[i][j-1])+a[j]; dp[i][j]表示前j个数取 i 段 ...
- 51Nod 1049 最大子段和
题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1049 #include<iostream> #i ...
- 51nod 1275 连续子段的差异
题目看这里 若[i,j]符合要求,那么[i,j]内的任何连续的子段都是符合要求的.我们可以枚举i,找到能合格的最远的j,然后ans+=(j-i+1). 那么问题就转换成了:在固定i的情况下,如何判断j ...
- 51Nod 1081:子段求和(前缀和)
1081 子段求和 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 收藏 关注 给出一个长度为N的数组,进行Q次查询,查询从第i个元素开始长度为l的子段所有元素之和 ...
- 51Nod 1049最大子段和 | 模板
Input示例 6 -2 11 -4 13 -5 -2 Output示例 20 1.最大子段和模板 #include "bits/stdc++.h" using namespace ...
- 51nod 1254 最大子段和 V2 ——单调栈
N个整数组成的序列a[1],a[2],a[3],…,a[n],你可以对数组中的一对元素进行交换,并且交换后求a[1]至a[n]的最大子段和,所能得到的结果是所有交换中最大的.当所给的整数均为负数时和为 ...
- (DP)51NOD 1049 最大子段和
N个整数组成的序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的连续子段和的最大值.当所给的整数均为负数时和为0. 例如:-2,11,-4,13,-5 ...
- 51nod 1254 最大子段和 V2
N个整数组成的序列a[1],a[2],a[3],…,a[n],你可以对数组中的一对元素进行交换,并且交换后求a[1]至a[n]的最大子段和,所能得到的结果是所有交换中最大的.当所给的整数均为负数时和为 ...
随机推荐
- FPGA的嵌入式乘法器
1. FPGA主要应用在并行处理资源的应用,视频与图像处理,无线通信的中频调制解调器. 嵌入式乘法器可以配置成一个 18 × 18 乘法器,或者配置成两个 9 × 9 乘法器.对于那些大于18 × 1 ...
- Extjs报错:isField为空或不是对象
在做Extjs开发的时候,有时候会碰到一个奇怪的问题,就是报错说"isField为空或不是对象",经过调试发现是一个数组,显示的长度是21,但是数组里面的个数只有 ...
- How to enable download EXE files from the Sharepoint website
As we all know,many applications have forbidden to upload and download exe files.Because the e ...
- kindeditor 限制上传图片大小及宽高
进入:/kindeditor/plugins/image/image.js,替换其中的 self.plugin.imageDialog = function (options)方法,代码为: self ...
- 更换ubuntu软件源的方法
第一步:查看本系统Codename 输入lsb_release -a查看本系统Codename,我的codename是bionic,如图: 第二步:搜索与codename对应的镜像地址 我搜索到的是: ...
- Manacher算法——最长回文子串
一.相关介绍 最长回文子串 s="abcd", 最长回文长度为 1,即a或b或c或d s="ababa", 最长回文长度为 5,即ababa s="a ...
- PHP+IIS上传大文件
最近刚接触IIS服务器,在使用php上传大文件的时候,遇到了一些问题.通过查阅网上资料进行了总结,希望对各位有帮助. 第一步,检查PHP的配置. 打开php.ini配置文件 1.file_upload ...
- epc笔记
http://wenku.baidu.com/view/5e921520dd36a32d7375812a.html 1. 先注册, EPC注册EPS业务或non-EPS服务 ?? HSS做什么? 2 ...
- 【转】给大家分享一下目前mlc颗粒的内存卡资料
以下信息是LZ从其它论坛上找到的TF卡也是有讲究的,一分价钱一分货 dboy99 楼主 骚(6) #1楼 2015-8-5 14:49引用Micro SD卡也叫TF卡,作为手机扩展存储空间的唯一方式用 ...
- HDU G-免费馅饼
http://acm.hdu.edu.cn/showproblem.php?pid=1176 Problem Description 都说天上不会掉馅饼,但有一天gameboy正走在回家的小径上,忽然 ...