炸弹

来源:互联网 发布:linux怎么启动gedit 编辑:程序博客网 时间:2024/04/28 23:54

炸弹


问题描述

高老大又在鼓捣炸弹了,这不,启动了一个了。
英明英勇的老大又在跟他的部下们表演空手光速拆炸弹了。
炸弹上是一个圆盘,圆盘上顺时针写着 N 个数。
其实这个炸弹就是要求从中选择若干个连续的数(注意每个数最多只能选一次)加起来,使得这些数字的和最大,然后输入这个最大的和,计时就会停止。
现在你被老大要求上台表演,时间是 1s,任务就交给你了。


输入

输入文件名为Bomb.in。
输入第一行包含一个正整数 N,表示数字的个数。
第二行包含 N 个整数,为所给的数字。


输出

输出文件名为Bomb.out。
输出包含一个整数,为最大的可以得到的和。


输入样例

8
2 -4 6 -1 -4 8 -1 3


输出样例

14


数据范围

对于 30% 的数据 1<=N<=200;
对于 70% 的数据 1<=N<=10000;
对于 100% 的数据 1<=N<=100000 , 答案在longint范围内。


Solution

首先,我们假设这不是一个环。
n 处把它断开。
然后就是 O(n) 求最大连续子序列。
环的情况怎么处理呢?
我们将一个方案分成两部分,一部分从 1 开始递增,一部分从 n 开始递减。
然后用动归就可以求出末端不超过 i 且从 1n 出发的最大连续子序列。


Code

#include <iostream>#include <cstdio>#define Max(x,y) ((x)>(y)?(x):(y))using namespace std;int n,ans;int w[100010];int f[100010];int f1[100010];int f2[100010];int s1[100010];int s2[100010];int main(){    freopen("bomb.in","r",stdin);    freopen("bomb.out","w",stdout);    scanf("%d",&n);    for(int i=1;i<=n;i++)        scanf("%d",&w[i]);    for(int i=1;i<=n;i++){        f[i]=Max(f[i-1]+w[i],w[i]);        s2[i]=s2[i-1]+w[i];        f2[i]=Max(f2[i-1],s2[i]);        ans=Max(ans,f[i]);    }    for(int i=n;i>=1;i--){        s1[i]=s1[i+1]+w[i];        f1[i]=Max(f1[i+1],s1[i]);        ans=Max(ans,f2[i-1]+f1[i]);    }    printf("%d\n",ans);    return 0;}
0 0