转载于:https://blog.youkuaiyun.com/dgq8211/article/details/7737451
题目链接:Click here~~
题意:
RT。
解题思路:
比较简单的dp,很容易推出状态转移方程:sum[i] = max{sum[i-1]+a[i],a[i]}. (sum[i]记录以a[i]为子序列末端的最大连续和.)
然后用一个值记录更新sum[i]的最大值即可。
即对于a[i]这个数字,我们考虑是否将它选入之前连续的序列。
如果选,状态变为sum[i-1]+a[i] ; 如果不选,则从此开始一个新的序列,故和为a[i]。
理解方程后,代码很好写了。
#include <stdio.h>
int main()
{
int z,n,max,sum;
int a,b,A,B,t;
scanf("%d",&z);
for(int k=1;k<=z;k++)
{
scanf("%d",&n);
sum = max = -1001;
for(int i=1;i<=n;i++)
{
scanf("%d",&t);
if(sum+t < t)
sum = t , a = b = i; //a、b记录当前连续子序列的起始、结束位置
else
sum += t , ++b;
if(max < sum)
max = sum , A = a , B = b;
}
printf("Case %d:\n%d %d %d\n",k,max,A,B);
if(k-z) puts("");
}
return 0;
}
如果没有要求写出起始点与终点,用分治法得:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int T,N,a[100005];
int maxsum(int *a,int x,int y)
{
if(y-x==1) return a[x];
int m = (y-x)/2+x;
int maxs = max(maxsum(a,x,m),maxsum(a,m,y));
int L,R,V;
V = 0;L = a[m-1];
for(int i=m-1;i>=1;i--)
L = max(L,V += a[i]);
V = 0;R = a[m];
for(int i=m;i<=y;i++)
R = max(R,V += a[i]);
return max(maxs,L+R);
}
int main()
{
scanf("%d",&T);
for(int i=1;i<=T;i++)
{
scanf("%d",&N);
for(int j=1;j<=N;j++)
{
scanf("%d",&a[j]);
}
printf("Case %d:\n",i);
printf("%d\n\n",maxsum(a,1,N));
}
return 0;
}