Max Sum

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 287192    Accepted Submission(s): 68202

Problem Description
Given a sequence a[1],a[2],a[3]......a[n], your job is to calculate the max sum of a sub-sequence. For example, given (6,-1,5,4,-7), the max sum in this sequence is 6 + (-1) + 5 + 4 = 14.
 

Input

The first line of the input contains an integer T(1<=T<=20) which means the number of test cases. Then T lines follow, each line starts with a number N(1<=N<=100000), then N integers followed(all the integers are between -1000 and 1000).
 

Output

For each test case, you should output two lines. The first line is "Case #:", # means the number of the test case. The second line contains three integers, the Max Sum in the sequence, the start position of the sub-sequence, the end position of the sub-sequence. If there are more than one result, output the first one. Output a blank line between two cases.
 

Sample Input

2
5 6 -1 5 4 -7
7 0 6 -1 1 -6 7 -5
 

Sample Output

Case 1:
14 1 4
Case 2:
7 1 6
 
概译:求一个数列最大连续和,即找到 1 ≤ i ≤ j ≤ n,使得a[ i ]+a[ i+1 ]+……+a[ j ]尽可能大,如有多组相同结果取最靠前的。
输入:测试组数;每行第一个数为n,然后输入a[ 1 ]~a[ n ]。
输出:Case %d:\n最大连续和 连续和的起始下标i 连续和的末尾下标j
思路:题是水题,这里我们探究一下时间和空间复杂度的优化。
1.枚举
ans=a[];
for(int i=;i<=n;i++)
for(int j=i;j<=n;j++)
{
//i和j是起点和终点
int sum=;
for(int k=i;k<=j;k++) sum+=a[i];
if(ans<sum)
ans=sum;
}

这大概是我们初学编程时的做法。

2.递推前缀和

sum[]=;
for(int i=;i<=n;i++)
sum[i]=sum[i-]+a[i];
for(int i=;i<=n;i++)
for(int j=i;j<=n;j++)
{
ans=max(ans,sum[j]-sum[i-]);
}

这样子就把一个区间的操作转化为了两个区间端点的操作,使得复杂度降到了O(n²)。然而面对1e5的数据量我们是没有勇气就这么提交的……

3.分治算法(O(nlogn))

以下借鉴刘汝佳《算法竞赛入门经典》中的思路。

①划分问题:把问题的实例划分成子问题;②递归求解:递归解决子问题;③合并问题:合并子问题的解得到原问题的解。

对于区间 [ l , r ],区间中点m,所求ans = max { l~m的ans,m+1~r的ans,由m连接的、占用了部分l~m和部分m+1~r的连续和 }。

我是用的map来记录的始末端点,详细请参见代码。哪里需要改正或可以精简之处万望指出。

 //140ms
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<map>
#define maxn 100005
#define inf 0x7fffffff
using namespace std; typedef pair<int,int> P;
int n,a[maxn];
map<P,P>mp;//记录区间[l,r]上的最大连续和的始末点pair(s,e) int Maxsum(int l,int r)
{
if(l==r)//返回条件
{
mp[P(l,r)]=P(,r);
return a[l];
} int m=(l+r)/;
int t=Maxsum(l,m),p=Maxsum(m+,r);//左边和右边的最大连续和
int cmp,flag=;
if(t<p)
{
cmp=p;
mp[P(l,r)]=mp[P(m+,r)];
flag=;
}
else
{
cmp=t;
mp[P(l,r)]=mp[P(l,m)];
}
//相连接的最大连续和
int L,R;
for(int i=m,j=inf;i>=l;i--)
if(j>=a[i])
j=a[i],L=i;
for(int i=m+,j=-inf;i<=r;i++)
if(j<a[i])
j=a[i],R=i; if(a[R]-a[L]>cmp||(a[R]-a[L]==cmp&&flag))//题中要求有多组相同结果时取最前面的结果,故而使用flag
{
cmp=a[R]-a[L];
mp[P(l,r)]=P(L+,R);
} return cmp;
}
int main()
{
int test,kase=;
scanf("%d",&test); while(test--)
{
scanf("%d",&n); for(int i=;i<=n;i++) scanf("%d",&a[i]),a[i]+=a[i-]; printf("Case %d:\n%d",++kase,Maxsum(,n));
//注意Maxsum过程中求得的mp,所以不能把这两行放在一起输出
printf(" %d %d\n",mp[P(,n)].first,mp[P(,n)].second);
if(test) printf("\n"); mp.clear();
} return ;
}

4.O(n)算法

还是以i为起点j为终点,则sum[ j ] - sum[ i-1 ]最大(参见第2种讨论)只要路过时顺便把在j之前最小的sum[ i-1 ]记录一下,就不需要遍历一遍了,直接减即可。代码中变量有点凌乱,见谅:

 //31ms
#include<cstdio> int a[];
int n,test,kase; int main()
{
scanf("%d",&test);
while(test--)
{
printf("Case %d:\n",++kase); scanf("%d",&n);
for(int i=;i<=n;i++) scanf("%d",&a[i]),a[i]+=a[i-]; int s=,e=,minn=,ans=-0x7fffffff;
//s即start,e即end,代表始末下标;
//minn是从j∈[1,i)中最小的a[j],ans为最大连续和初始值设为最小以更新
for(int i=,j=;i<=n;i++)//j作为临时记录用
{
if(a[i]-minn>ans) ans=a[i]-minn,s=j,e=i;//更新结果
if(minn>a[i]) minn=a[i],j=i;//更新minn
} printf("%d %d %d\n",ans,++s,e);
if(test) printf("\n");
}
return ;
}

5.减少空间使用

不需要开数组,只要贪心地每读入一个数,sum就加上这个数,若是比ans大,则ans更新为sum;若是sum<0了,则sum置0,因为前面一堆负数只会是后面的正数的累赘,不可能比后面的正数更优。至于后面的正数能不能把ans更新,就要看它能力了。

这依旧是O(n)的算法,所以运行时间没变,但是减少了空间的使用!

另,此代码中使用了读入挂来减少输入的所需时间,使得评测结果更优。虽然网上有很多快速读入的模板,不过AlphaWA感觉有点长有点乱,就东拼西凑瞎搞了一个。如果此种写法有bug,希望同学们指出!

 //31ms,scanf替换为普通getchar快速读为46ms,替换为fread快速读为0ms
#include<cstdio> //以下变量均为读入挂所需
const int maxl=1e2;
//这里maxl是每次fread分块读入输入文件的长度,赋值为多少都可以
//由于有pos==len时pos归零的操作,可以使一个长文件分为若干个长度为maxl的文件读入
int pos,len;
char buf[maxl]; int xchar()
{
if(pos==len) pos=,len=fread(buf,,maxl,stdin);
return buf[pos++];
}
int read()
{
int x=,s=,c=xchar();
while(c<=) c=xchar();
if(c=='-') s=-,c=xchar();
for(;c>=''&&c<='';c=xchar()) x=x*+c-'';
return x*s;
}
int main()
{
int test,kase=;
test=read(); while(test--)
{
int n,sum=,ans=-,s,e,temp=;
n=read(); for(int i=;i<=n;i++)
{
int a;
a=read();
sum+=a;
if(sum>ans)
{
ans=sum;
s=temp;
e=i;
}
if(sum<)
{
sum=;
temp=i+;
}
} printf("Case %d:\n%d %d %d\n",++kase,ans,s,e);
if(test) printf("\n");
} return ;
}

END~

HDU-1003:Max Sum(优化)的更多相关文章

  1. HDU 1003 Max Sum --- 经典DP

    HDU 1003    相关链接   HDU 1231题解 题目大意:给定序列个数n及n个数,求该序列的最大连续子序列的和,要求输出最大连续子序列的和以及子序列的首位位置 解题思路:经典DP,可以定义 ...

  2. HDOJ(HDU).1003 Max Sum (DP)

    HDOJ(HDU).1003 Max Sum (DP) 点我挑战题目 算法学习-–动态规划初探 题意分析 给出一段数字序列,求出最大连续子段和.典型的动态规划问题. 用数组a表示存储的数字序列,sum ...

  3. hdu 1003 Max Sum (DP)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1003 Max Sum Time Limit: 2000/1000 MS (Java/Others)   ...

  4. HDU 1003 Max Sum【动态规划求最大子序列和详解 】

    Max Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Sub ...

  5. hdu 1003 MAX SUM 简单的dp,测试样例之间输出空行

    测试样例之间输出空行,if(t>0) cout<<endl; 这样出最后一组测试样例之外,其它么每组测试样例之后都会输出一个空行. dp[i]表示以a[i]结尾的最大值,则:dp[i ...

  6. HDU 1003 Max Sum (动规)

    Max Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Su ...

  7. hdu 1003 Max sum(简单DP)

    Max Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Problem ...

  8. HDU 1003 Max Sum

    Max Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Sub ...

  9. HDU 1003 Max Sum 解题报告

    题目大意:求一串数字中,几个连续数字加起来最大值,并确定起始和最末的位置. 思路:这是一题DP题,但是可以用尺取法来做.我一开始不会,也是看了某大神的代码,然后有人告诉我这是尺取法,现在会了. //尺 ...

  10. HDU 1003 Max Sum(AC代码)

    #include <stdio.h> int main(){ int i,t,j,n,x; int start,end,temp,max,sum; scanf("%d" ...

随机推荐

  1. bzoj4474: [Jsoi2015]isomorphism

    树hash啊 我的做法很垃圾,就是yy一种只有一个孩子时hash值和孩子一样的hash法 然后用重心去作为根遍历 这样有点问题,就是重心假如也是要删掉的那就gg了 那我们求tot的时候删掉的点就不管直 ...

  2. LightOJ - 1030 Discovering Gold —— 期望

    题目链接:https://vjudge.net/problem/LightOJ-1030 1030 - Discovering Gold    PDF (English) Statistics For ...

  3. BZOJ 2023 [Usaco2005 Nov]Ant Counting 数蚂蚁:dp【前缀和优化】

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2023 题意: 有n个家族,共m只蚂蚁(n <= 1000, m <= 1000 ...

  4. SpringMVC 注释@PathVariable

    @PathVariable 是用来获得请求url中的动态参数的: @ResponseBody @RequestMapping(value="/pointUpload/{userid}&quo ...

  5. java 基于百度地图API GPS经纬度解析地址

    首先这是百度地图api 的接口地址,基于接口的参数,不过多介绍,其中都提供相应的介绍: http://lbsyun.baidu.com/index.php?title=webapi/guide/web ...

  6. UVA-10534 (LIS)

    题意: 给定一个长为n的序列,求一个最长子序列,使得该序列的长度为2*k+1,前k+1个数严格递增,后k+1个数严格单调递减; 思路: 可以先求该序列最长单调递增和方向单调递增的最长序列,然后枚举那第 ...

  7. python中通过xlwt、xlrd和xlutils操作xls

    xlwt模块用于在内存中生成一个xls/xlsx对象,增加表格数据,并把内存中的xls对象保存为本地磁盘xls文件; xlrd模块用于把本地xls文件加载到内存中,可以读取xls文件的表格数据,查询x ...

  8. chan_ss7 呼出的时候指定使用某个CICs,或者CICs范围 的方法

      Linkset one: 1-31 Incoming 33-58 Outgoing 58-63 Emergency Traffic Linkset two: 1-31 Incoming 33-58 ...

  9. testing

    doctest_test.py def square(x): ''' 这里需要空格 >>> square(2) 4 啦啦 >>> square(3) 9 上不一行能 ...

  10. Python框架下django 的并发和多线程

    django 的并发能力真的是令人担忧,django本身框架下只有一个线程在处理请求,任何一个请求阻塞,就会影响另一个情感求的响应,尤其是涉及到IO操作时,基于框架下开发的视图的响应并没有对应的开启多 ...