[GESP202503 六级] 环线(含视频)

视频讲解:GESP202503 六级 环线-信息学奥赛GESP等级考试真题解析

一、原题

题目描述

小 A 喜欢坐地铁。地铁环线有 n 个车站,依次以 1,2,⋯,n 标号。车站 i (1≤i<n) 的下一个车站是车站 i+1。特殊地,车站 n 的下一个车站是车站 1。

小 A 会从某个车站出发,乘坐地铁环线到某个车站结束行程,这意味着小 A 至少会经过一个车站。小 A 不会经过一个车站多次。当小 A 乘坐地铁环线经过车站 i 时,小 A 会获得 ai​ 点快乐值。请你安排小 A 的行程,选择出发车站与结束车站,使得获得的快乐值总和最大。

输入格式

第一行,一个正整数 n,表示车站的数量。

第二行,n 个整数 ai​,分别表示经过每个车站时获得的快乐值。

输出格式

一行,一个整数,表示小 A 能获得的最大快乐值。

输入输出样例

输入 #1

复制代码
4
-1 2 3 0

输出 #1

复制代码
5

输入 #2

复制代码
5
-3 4 -5 1 3

输出 #2

复制代码
5

说明/提示

对于 20% 的测试点,保证 1≤n≤200。

对于 40% 的测试点,保证 1≤n≤2000。

对于所有测试点,保证 1≤n≤2×10^5,−10^9≤ai​≤10^9。

二、做题思路

1)填充数据

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int m=200005;
long long a[m];
int main(){
	//1)填充数据
	//1.1)确定车站数量n
	int n;cin>>n; 
	//1.2)填充n个车站的快乐值
	for(int i=1;i<=n;i++) cin>>a[i];
	return 0;
} 

2)动态规划:求最大/小子段和

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int m=200005;
long long a[m];
long long max_dp[m],min_dp[m];
long long max_sum,min_sum;
int main(){
	//1)填充数据
	//... 
	//2)动态规划:求最大/小子段和
	//2.1)初始化dp
	max_sum=min_sum=max_dp[1]=min_dp[1]=a[1];
	//2.2)计算当前最优=最优(累加之前,不累加之前) 
	for(int i=2;i<=n;i++){
		//计算当前最优 
		max_dp[i]=max(a[i]+max_dp[i-1],a[i]);
		min_dp[i]=min(a[i]+min_dp[i-1],a[i]);
		//比较找出所有最优中的最优 
		max_sum=max(max_dp[i],max_sum);
		min_sum=min(min_dp[i],min_sum);
	}
	return 0;
} 

3)计算总和 和 最大值

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int m=200005;
long long a[m];
long long max_dp[m],min_dp[m];
long long max_sum,min_sum;
int main(){
	//1)填充数据
	//... 
	//2)动态规划:求最大/小子段和
	//2.1)初始化dp
	long long maxx=a[1],sum=a[1];
	max_sum=min_sum=max_dp[1]=min_dp[1]=a[1];
	//2.2)计算当前最优=最优(累加之前,不累加之前) 
	for(int i=2;i<=n;i++){
		//计算当前最优 
		max_dp[i]=max(a[i]+max_dp[i-1],a[i]);
		min_dp[i]=min(a[i]+min_dp[i-1],a[i]);
		//比较找出所有最优中的最优 
		max_sum=max(max_dp[i],max_sum);
		min_sum=min(min_dp[i],min_sum);
		//3)计算总和 和 最大值
		sum+=a[i];
		maxx=max(maxx,a[i]);
	}
	return 0;
} 

4)输出结果

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int m=200005;
long long a[m];
long long max_dp[m],min_dp[m];
long long max_sum,min_sum;
int main(){
	//1)填充数据
	//... 
	//2)动态规划:求最大/小子段和
	//....
		//3)计算总和 和 最大值
		//...
	//4)输出结果
	//4.1)全是负数 ,输出最大值
	if(maxx<0) cout<<maxx;
	//4.2)否输输出最优 max(最大子段和,总和-最小子段和)
	else{
		cout<<max(max_sum,sum-min_sum);
	}
	return 0;
} 

三、答案

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int m=200005;
long long a[m];
long long max_dp[m],min_dp[m];
long long max_sum,min_sum;
int main(){
	//1)填充数据
	//1.1)确定车站数量n
	int n;cin>>n; 
	//1.2)填充n个车站的快乐值
	for(int i=1;i<=n;i++) cin>>a[i];
	//2)动态规划:求最大/小子段和
	//2.1)初始化dp
	long long maxx=a[1],sum=a[1];
	max_sum=min_sum=max_dp[1]=min_dp[1]=a[1];
	//2.2)计算当前最优=最优(累加之前,不累加之前) 
	for(int i=2;i<=n;i++){
		//计算当前最优 
		max_dp[i]=max(a[i]+max_dp[i-1],a[i]);
		min_dp[i]=min(a[i]+min_dp[i-1],a[i]);
		//比较找出所有最优中的最优 
		max_sum=max(max_dp[i],max_sum);
		min_sum=min(min_dp[i],min_sum);
		//3)计算总和 和 最大值
		sum+=a[i];
		maxx=max(maxx,a[i]);
	}
	//4)输出结果
	//4.1)全是负数 ,输出最大值
	if(maxx<0) cout<<maxx;
	//4.2)否输输出最优 max(最大子段和,总和-最小子段和)
	else{
		cout<<max(max_sum,sum-min_sum);
	}
	
	return 0;
} 
相关推荐
CQU_JIAKE1 小时前
10.15【A】
算法
晴天的雨.9921 小时前
【C++】模板进阶
开发语言·c++·算法
木井巳2 小时前
【动态规划】三步问题
java·算法·leetcode·动态规划·推荐算法
楚识科技2 小时前
手写 OCR 识别技术深度解析:从算法原理到政企级落地实现
算法·ocr
leobertlan10 小时前
痛苦系列 | DSP-03 跨越单位圆:Z变换与零极点分析
算法·程序员
蛋蛋的就会顺顺的10 小时前
hot100 p0——栈,贪心算法,动态规划
java·前端·javascript·算法·leetcode·力扣
开发小能手12311 小时前
答案daanC语言
数据结构·算法
Navigator_Z13 小时前
LeetCode //C - 1291. Sequential Digits
c语言·算法·leetcode
pride.li14 小时前
第03章 Python 教程-基础语法:注释与变量
服务器·前端·后端·python·算法·计算机视觉