题目:
聪明的LJY发明了一个小游戏,他在地上花了n个格子里面有数字的格子,所有格子从左到右依次排列。
规则:
(1)玩家可以选择任意一个位置,并走到这个格子上。
(2)玩家需要根据自己脚下格子中的数字向右走这个数字个数的格子。
(3)当走过最后一个格子时游戏结束。
(4)玩家所经过(停留过的格子)数字的总和为游戏得分,包含起始位置。作为发明这个游戏的发明者,LJY不想自己输给其他玩家,请你帮助他得到这个游戏最高的分数。
输入格式:
每个测试用例的第一行包含一个整数n(1≤n≤2×10^6) ———— 数组 a 的长度。
接下来一行包含n个整数a1,a2,…,an(1≤ai≤10^9) ———— 数组 a 的元素。输出格式:
输出一个数字 ———— 表示LJY可以获得的最大得分。请注意,LJY可以选择任何1到n之间的起始位置,以最大化他的结果。
输入样例:
5
7 3 1 2 3
输出样例:
7
解题思路:
开始思路:
如果从每一个位置开始枚举,寻找最大值会造成O(n*n)的复杂度,由于数据量是2*10^6,因此会超时。
优化思想:
如果使用枚举的话,考虑每个位置i,当从i出发时路线是唯一的,因此在枚举路径上的其他点的值时,会导致重复计算。因此可以使用动态规划思想,从后向前求,把一条路径上所经过的点记忆化,这样在计算前一个点的值时可以直接使用,这样可以优化到O(N)的复杂度。
AC代码:
#define _CRT_SECURE_NO_WARNINGS
#pragma comment(linker, "/STACK:1024000000,1024000000")
//#include<bits/stdc++.h>
#include<iostream>
#include<string>
#include<cmath>
#include<vector>
#include<algorithm>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<list>
#include<cstdlib>
using namespace std;
#define arrout(a,n) rep(i,1,n)std::cout<<a[i]
#define arrin(a,n) rep(i,1,n)std::cin>>a[i]
#define _for(i,a,b) for( int i=(a); i<(b); ++i)
#define _rep(i,a,b) for( int i=(a); i<=(b); ++i)
#define _dep(i,a,b) for( int i=(a); i>=(b); --i)
#define mem(a,x) memset(a,x,sizeof a)
#define all(x) x.begin(),x.end()
#define arrall(a,n) a+1,a+1+n
#define PII std::pair<int,int>
#define m_p std::make_pair
#define endl '\n'
#define ff first
#define ss second
#define CD const double
#define CI const int
#define int long long
#define itn int
#define PI 3.14159
CI N = 1e9 + 9, MAXI = 0x3f3f3f3f, MINI = -0x3f3f3f3f, MOD = 1e9 + 7;
int dx[] = { 0, 1, 0,-1, 1, 1,-1,-1, 0 };
int dy[] = { 1, 0,-1, 1, 1,-1,-1, 1, 0 };
// dp存从某一点开始的值
int n, arr[2000005],dp[2000005];
signed main()
{
//cin.tie(0), cout.tie(0), ios::sync_with_stdio(0);
//输入:
cin >> n;
for (int i = 0; i < n; ++i) cin >> arr[i];
//从后向前做处理:
int max = 0;
for (int i = n - 1; i >= 0; --i)
{
dp[i] = arr[i];
int next = i + arr[i];
//如果大于了数组长度则不做处理
if (next < n)
{
dp[i] += dp[next];
}
if (dp[i] > max)
{
max = dp[i];
}
}
cout<<max;
return 0;
}