Codevs 1648 最大和

1648 最大和
时间限制: 1 s
空间限制: 256000 KB
题目等级 : 钻石 Diamond
传送门
题目描述 Description
N个数围成一圈,要求从中选择若干个连续的数(注意每个数最多只能选一次)加起来,问能形成的最大的和。
输入描述 Input Description
第一行输入N,表示数字的个数,第二行输入这N个数字。
输出描述 Output Description
输出最大和。
样例输入 Sample Input
8
2 -4 6 -1 -4 8 -1 3
样例输出 Sample Output
14
数据范围及提示 Data Size & Hint
数据说明:
40% 1<=N<=300
60% 1<=N<=2000
100% 1<= N<=100000,答案在longint范围内.

/*
T. 
连成环啊连成环.
赶脚数据中负数应该不少.
所以复杂度在o(n^2/2)~o(n^2)之间.
然后10^10 华丽丽的T了.
10^5范围应该考虑logn,log^2n,nlogn…… 
*/
#include<iostream>
#include<cstdio>
#define MAXN 100001*2
#define LL long long
using namespace std;
LL f[MAXN],n,x,s[MAXN],tot=-1e18;
LL read()
{
    LL x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=x*10+ch-48,ch=getchar();
    return x*f;
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)  x=read(),s[i]=s[i+n]=x;
    for(int i=1;i<=n;i++){
        if(s[i]>0)
        {
            f[i]=s[i];tot=max(tot,f[i]);
            for(int j=i+1;j<i+n;j++){
              if(f[j-1]>0) f[j]=f[j-1]+s[j];
              else f[j]=x;
            tot=max(tot,f[j]);
            }
        }
        tot=max(s[i],tot);
    }
    printf("%lld",tot);
    return 0;
}
/*
一开始怎么也没想到orz.
其实还是挺好想的.
答案的贡献来自于
(1)连续和(不跨环).
(2)连续和(跨环).
不跨环的o(n)扫一遍即可.
跨环的因为所有数的价值和是一定的
只需求出最小连续和用价值总和减掉即可(显然).
最后两者取大. 
*/
#include<iostream>
#include<cstdio>
#define LL long long
#define MAXN 100001
using namespace std;
LL x,tot1,tot2,tot,n,ans1=-1e12,ans2=1e12;
LL read()
{
    LL x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=x*10+ch-48,ch=getchar();
    return x*f;
}
int main()
{
    n=read();x=read();
    tot=tot1=tot2=x;
    for(int i=2;i<=n;i++)
    {
        x=read();
        if(tot1>0) tot1+=x;
        else tot1=x;
        if(tot2<0) tot2+=x;
        else tot2=x;
        tot+=x;
        ans1=max(ans1,tot1),ans2=min(ans2,tot2);
    }
    printf("%lld",max(tot-ans2,ans1));
    return 0;
}
原文地址:https://www.cnblogs.com/nancheng58/p/6070804.html