POJ 3415 Max Sum of Max-K-sub-sequence (线段树+dp思想)
Max Sum of Max-K-sub-sequence
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 5084 Accepted Submission(s): 1842
Now your job is to calculate the max sum of a Max-K-sub-sequence. Max-K-sub-sequence means a continuous non-empty sub-sequence which length not exceed K.
Then T lines follow, each line starts with two integers N , K(1<=N<=100000 , 1<=K<=N), then N integers followed(all the integers are between -1000 and 1000).
6 3
6 -1 2 -6 5 -5
6 4
6 -1 2 -6 5 -5
6 3
-1 2 -6 5 -5 6
6 6
-1 -1 -1 -1 -1 -1
7 1 3
7 6 2
-1 1 1
题目大意:T 组数据,求 n 个数 连续子串的最大和是多少,子串要求长度不超过 k,以及这是个环形,如果多解,满足起点be最小,其次终点en最小
解题思路:枚举每个起点be,终点en一定是在 be<=en<=be+k-1 这个范围内,所以求这个范围内的连续最长和即可,可以用 sum[en] -sum[be-1] ,其中sum[x]表示前x个数的和,所以即选出 be<=en<=be+k-1这个范围内最大sum[i],用线段树过了,但是rmq算法超时,郁闷!
线段树算法,AC
#include <iostream>
#include <cmath>
#include <cstdio>
using namespace std; const int maxn=200010;
int d[maxn],sum[maxn],n,k,mx,mn; struct node{
int l,r,minc,maxc;
}a[4*maxn]; void input(){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%d",&d[i]);
d[i+n]=d[i];
}
sum[0]=0;
for(int i=1;i<=2*n;i++) sum[i]=sum[i-1]+d[i];
} void build(int l,int r,int k){
a[k].l=l;
a[k].r=r;
if(l<r){
int mid=(l+r)/2;
build(l,mid,2*k);
build(mid+1,r,2*k+1);
a[k].maxc=max(a[2*k].maxc,a[2*k+1].maxc);
a[k].minc=min(a[2*k].minc,a[2*k+1].minc);
}else{
a[k].maxc=sum[l];
a[k].minc=sum[l];
}
} void query(int l,int r,int k){
if(l<=a[k].l && a[k].r<=r){
//cout<<a[k].maxc<<" "<<a[k].minc<<endl;
mx=max(mx,a[k].maxc);
mn=min(mn,a[k].minc);
}else{
int mid=(a[k].l+a[k].r)/2;
if(r<=mid) query(l,r,2*k);
else if(l>=mid+1) query(l,r,2*k+1);
else{
query(l,mid,2*k);
query(mid+1,r,2*k+1);
}
}
} void computing(){
build(0,2*n,1);
int ans=-(1<<30),be=1,en=1;
for(int i=1;i<=n;i++){
mx=-(1<<30);
query(i,i+k-1,1);
if(mx-sum[i-1]>ans){
ans=mx-sum[i-1];
be=i;
}
}
for(int i=be;i<=be+k-1;i++){
if(sum[i]-sum[be-1]==ans){
en=i;
break;
}
}
printf("%d %d %d\n",ans,be>n?be-n:be,en>n?en-n:en);
} int main(){
int t;
scanf("%d",&t);
while(t-- >0){
input();
computing();
}
return 0;
}
rmq算法,超时,郁闷中
#include <iostream>
#include <cmath>
#include <cstdio>
using namespace std; const int maxn=300005*2;
int maxsum[maxn][20],minsum[maxn][20],flog[maxn],d[maxn],sum[maxn],n,k; void ini(){
int r=2,cnt=0;
for(int i=1;i<maxn;i++){
if(i<r) flog[i]=cnt;
else{
flog[i]=++cnt;
r=r<<1;
}
}
} void input(){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%d",&d[i]);
d[i+n]=d[i];
}
} void getrmq(){
for(int i=1;i<=2*n;i++){
sum[i]=sum[i-1]+d[i];
maxsum[i][0]=sum[i];
minsum[i][0]=sum[i];
}
for(int j=1;j<=flog[2*n];j++)
for(int i=1;i<=2*n;i++){
if(i+(1<<j)-1<=2*n){
maxsum[i][j]=max(maxsum[i][j-1],maxsum[i+(1<<(j-1))][j-1]);
minsum[i][j]=min(minsum[i][j-1],minsum[i+(1<<(j-1))][j-1]);
}
}
} void computing(){
getrmq();
int ans=-(1<<30),be=1,en=1,l,r,x,tmp;
for(int i=1;i<=n;i++){
l=i,r=i-1+k,x=flog[r-l+1];
tmp=max(maxsum[l][x],maxsum[r-(1<<x)+1][x]);
if(tmp-sum[i-1]>ans){
ans=tmp-sum[i-1];
be=i;
}
}
for(int i=be;i<=be+k-1;i++){
if(sum[i]-sum[be-1]==ans){
en=i;
break;
}
}
printf("%d %d %d\n",ans,be>n?be-n:be,en>n?en-n:en);
} int main(){
ini();
int t;
scanf("%d",&t);
while(t-- >0){
input();
computing();
}
return 0;
}
POJ 3415 Max Sum of Max-K-sub-sequence (线段树+dp思想)的更多相关文章
- POJ 2014.K-th Number 区间第k小 (归并树)
K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 57543 Accepted: 19893 Ca ...
- 【CF280D】k-Maximum Subsequence Sum(大码量多细节线段树)
点此看题面 大致题意: 给你一个序列,让你支持单点修改以及询问给定区间内选出至多\(k\)个不相交子区间和的最大值. 题意转换 这道题看似很不可做,实际上可以通过一个简单转换让其变可做. 考虑每次选出 ...
- K - Japan(线段树)
Japan plans to welcome the ACM ICPC World Finals and a lot of roads must be built for the venue. Jap ...
- Codeforces 1303G - Sum of Prefix Sums(李超线段树+点分治)
Codeforces 题面传送门 & 洛谷题面传送门 个人感觉这题称不上毒瘤. 首先看到选一条路径之类的字眼可以轻松想到点分治,也就是我们每次取原树的重心 \(r\) 并将路径分为经过重心和不 ...
- poj 2777(线段树+lazy思想) 小小粉刷匠
http://poj.org/problem?id=2777 题目大意 涂颜色,输入长度,颜色总数,涂颜色次数,初始颜色都为1,然后当输入为C的时候将x到y涂为颜色z,输入为Q的时候输出x到y的颜色总 ...
- POJ 2750 Potted Flower(线段树+dp)
题目链接 虽然是看的别的人思路,但是做出来还是挺高兴的. 首先求环上最大字段和,而且不能是含有全部元素.本来我的想法是n个元素变为2*n个元素那样做的,这样并不好弄.实际可以求出最小值,总和-最小,就 ...
- bzoj3110 [Zjoi2013]K大数查询——线段树套线段树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3110 外层权值线段树套内层区间线段树: 之所以外层权值内层区间,是因为区间线段树需要标记下传 ...
- bzoj 3110 [Zjoi2013]K大数查询——线段树套线段树(标记永久化)
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3110 第一道线段树套线段树! 第一道标记永久化! 为什么为什么写了两个半小时啊…… 本想线段 ...
- POJ 3468 A Simple Problem with Integers(详细题解) 线段树
这是个线段树题目,做之前必须要有些线段树基础才行不然你是很难理解的. 此题的难点就是在于你加的数要怎么加,加入你一直加到叶子节点的话,复杂度势必会很高的 具体思路 在增加时,如果要加的区间正好覆盖一个 ...
随机推荐
- 简单的方式实现javascript 小数取整
JS: function truncateNumber(n){ return n|0; } 測试: console.log(truncateNumber(12.345)); 浏览器打印出12
- Activity的绘制流程简单分析(基于android 4.0源码进行分析)
要明白这个流程,我们还得从第一部开始,大家都知道 在activity里面 setcontentview 调用结束以后 就可以看到程序加载好我们的布局文件了,从而让我们在手机上看到这个画面. 那么我们来 ...
- while和do while习题
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace 练习 { ...
- 在Qt中如何使用QtDesigner创建的UI文件
使用Qt有一些时间了,一直在IDE环境(qtcreator和VS2003+集成器)中使用,自然少了很多麻烦的步骤.但是在享受这种便利的同 时,我们也失去了理解更多知识背后的点滴.在IDE中,如果我们要 ...
- VMware machine里的文件
.nvram——虚拟机BIOS或EFI配置文件. .vmdk——虚拟磁盘特性文件,是存放虚拟磁盘当前状况和上次执行快照时的状况之间的差异的快照文件. .vmsd——虚拟机快照,包含虚拟机快照信息的数据 ...
- 操作PDF文档功能的相关开源项目探索——iTextSharp 和PDFBox
原文 操作PDF文档功能的相关开源项目探索——iTextSharp 和PDFBox 很久没自己写写心得日志与大家分享了,一方面是自己有点忙,一方面是自己有点懒,没有及时总结.因为实践是经验的来源,总结 ...
- linux下crontab的使用方法
<span style="font-size:14px;">在Linux中任务可以被配置在指定的时间段.指定的日期.或系统平均载量低于指定的数量时自动运行. cront ...
- android 定时拍照并发送微博
最近在做android方面的开发,下面是android自动对焦并拍照的小例子: package com.comnvi.camera; import java.io.File; import java. ...
- 根据li标签 查找class="alcw4 alcw41"对应的值
jrhmpt01:/root/lwp/0526# cat a2.pl use LWP::UserAgent; use DBI; use POSIX; use Data::Dumper; use HTM ...
- http协议与web本质
当你在浏览器地址栏敲入“http://www.csdn.net/”,然后猛按回车,呈现在你面前的,将是csdn的首页了(这真是废话,你会认为这是理所当然的).作为一个开发者,尤其是web开发人员,我想 ...