【题解】【动态规划】【洛谷P11963】[GESP202503 六级] 环线
P11963 [GESP202503 六级] 环线
题目描述
小 A 喜欢坐地铁。地铁环线有 n n n 个车站,依次以 1 , 2 , ⋯ , n 1,2,\cdots,n 1,2,⋯,n 标号。车站 i ( 1 ≤ i < n ) i\ (1\leq i<n) i (1≤i<n) 的下一个车站是车站 i + 1 i+1 i+1。特殊地,车站 n n n 的下一个车站是车站 1 1 1。
小 A 会从某个车站出发,乘坐地铁环线到某个车站结束行程,这意味着小 A 至少会经过一个车站。小 A 不会经过一个车站多次。当小 A 乘坐地铁环线经过车站 i i i 时,小 A 会获得 a i a_i ai 点快乐值。请你安排小 A 的行程,选择出发车站与结束车站,使得获得的快乐值总和最大。
输入格式
第一行,一个正整数 n n n,表示车站的数量。
第二行, n n n 个整数 a i a_i ai,分别表示经过每个车站时获得的快乐值。
输出格式
一行,一个整数,表示小 A 能获得的最大快乐值。
输入输出样例
输入 #1
4
-1 2 3 0
输出 #1
5
输入 #2
5
-3 4 -5 1 3
输出 #2
5
说明/提示
对于 20 % 20\% 20% 的测试点,保证 1 ≤ n ≤ 200 1\leq n\leq 200 1≤n≤200。
对于 40 % 40\% 40% 的测试点,保证 1 ≤ n ≤ 2000 1\leq n\leq 2000 1≤n≤2000。
对于所有测试点,保证 1 ≤ n ≤ 2 × 10 5 1\leq n\leq 2\times 10^5 1≤n≤2×105, − 10 9 ≤ a i ≤ 10 9 -10^9\leq a_i\leq 10^9 −109≤ai≤109。
1.思路解析
形式化题意
对于一个环,求他的最大字段和。
推导
首先,对于一个环,如下图:
我们可以将他从某一条边分开,从而变成一个序列。
从 1 1 1和 2 2 2之间分,序列变成
1 0 -4 2 -1 4 3 2
。
从 2 2 2和 3 3 3之间分,序列变成2 1 0 -4 2 -1 4 3
。
…
我们要在环上选起点和终点,假设我们选择
l
=
2
,
r
=
−
1
l=2,r=−1
l=2,r=−1的节点,在环上表示:
我们把他表示到序列上,如序列为2 1 0 -4 2 1 4
的情况。
发现,如果要选取一段,只有两种情况:
(1)选的在序列中间
(2)选的不在序列中间,观察可知,这种一定是序列的前缀和后缀拼在一起的。
所以,我们只要对这两种,都求出最大值,最后取个 m a x max max就可以了。
定义
f
1
i
f1_i
f1i表示前i
个中最大的前缀和,
f
2
i
f2_i
f2i表示后i
个中最大的后缀和,预处理
出
f
1
,
f
2
f1,f2
f1,f2,即可避免重复。最后,在对这个序列,跑一遍最大子段和,取个
m
a
x
max
max就可以了,还需要记得开long long
。
2.AC代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int f1[200005],f2[2000005],a[200005];
signed main(){
int n;
cin>>n;
for (int i=1;i<=n;i++)cin>>a[i];
int sum=0,maxn=-1e9;
for (int i=1;i<=n;i++) {
sum+=a[i];
maxn=max(maxn,sum);
f1[i]=maxn;
}
sum=0,maxn=-1e9;
for (int i=n;i>=1;i--) {
sum+=a[i];
maxn=max(maxn,sum);
f2[i]=maxn;
}
int cnt=-1e9; // 第一种情况的最大值
sum=0;
for (int i=1;i<=n;i++){
if (sum<0)sum=a[i];
else sum+=a[i];
cnt=max(cnt,sum);
}
int cnt2=-1e9; // 第二种情况的最大值
for (int i=1;i<=n;++i)
cnt2=max(max(cnt2,f1[i]+f2[i+1]),f1[i-1]+f2[i]);
cout<<max(cnt,cnt2);
return 0;
}
最后,制作不易,希望大家多多点赞收藏,关注下微信公众号,谢谢大家的关注,您的支持就是我更新的最大动力!
公众号上会及时提供信息学奥赛的相关资讯、各地科技特长生升学动态、还会提供相关比赛的备赛资料、信息学学习攻略等。