(最大连续和)
小学生一发
一道环状的最大连续和。
蒜厂年会
题目描述:
在蒜厂年会上有一个抽奖,在一个环形的桌子上,有
n
n
n个纸团,每个纸团上写一个数字,表示你可以得到多少蒜币。但是这个游戏比较坑,里面竟然有负数,表示你要支付多少蒜币。因为这些数字都是可见的,所以大家都是不会出现的陪的情况。
游戏规则:每人只能抓一次,只能抓取一段连续的纸团,所有纸团是那个的数字和就是你可以获得的蒜币。
蒜头君作为蒜厂的一员在想,我怎么可以获得最多的蒜币呢?最多能获取多少蒜币呢?
因为年会是发奖,那么一定有大于0的纸团。
输入:
第一行输入一个整数
n
n
n,表示有
n
n
n个纸团。
(
n
≤
1
0
5
)
(n\leq 10^5)
(n≤105)
第二行输入
n
n
n个整数
a
i
a_i
ai, 表示每个纸团上面写的数字
(这些纸团的输入顺序就是环形桌子上纸团的摆放顺序)。
(
−
1
0
9
≤
a
i
≤
1
0
9
)
(-10^9 \leq a_i\leq 10^9)
(−109≤ai≤109)
输出:
输出一个整数,表示蒜头君最多能获取多少蒜币。
解析
本题是最大连续和的一个变形,把序列变成环形了而已。怎么求呢,首先肯定要先求出序列的最大连续和,这个直接分治法或者 d p dp dp一下就完事了。考虑到最大值可能存在首尾相接上,这样我们就需要引入数组 s u m sum sum, s u m i sum_i sumi表示从 1 1 1到 i i i的前缀和中的最大值,这样就只需要统计后缀和,再加上前缀和的最大值就行。
AC代码:
// 小学生一发的刷题之路
// 最大连续和-环状
// dp,前缀和;
//
//
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#include <queue>
#include <deque> //双向队列;
#include <cmath>
#include <set>
#include <stack>
#include <map>
#include <vector>
#include <cstdlib>
#include <iomanip>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const double PI=acos(-1.0);
const double eps=1e-8;
const double e=exp(1.0);
const int maxn=1e5+5;
const int maxm=1e6+5;
const ll mod=1e9+7;
const int INF=1e8;
template<class T>
void read(T &ret){ //快速输入模版;
ret=0;
int f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
ret=ret*10+c-'0';
c=getchar();
}
ret*=f;
}
int n;
ll a[maxn],dp[maxn],sum[maxn];
int main()
{
memset(sum,0,sizeof(sum));
scanf("%d",&n);
ll ans1=0,tmp=0,maxa=0;
dp[0]=0,sum[0]=0;
for(int i=1;i<=n;i++){
read(a[i]);
tmp+=a[i];
maxa=max(maxa,tmp);
sum[i]=maxa;
if(dp[i-1]>0){
dp[i]=dp[i-1]+a[i];
}else{
dp[i]=a[i];
}
ans1=max(ans1,dp[i]);
}
ll ans2=0,max_tmp=0;
tmp=0;
for(int i=n;i>=1;i--){
tmp+=a[i];
max_tmp=max(max_tmp,tmp);
ans2=max(ans2,sum[i-1]+max_tmp);
}
printf("%lld\n",max(ans1,ans2));
return 0;
}
新的开始,每天都要快乐哈。