题目描述
教主有着一个环形的花园,他想在花园周围均匀地种上 n 棵树,但是教主花园的土壤很特别,每个位置适合种的树都不一样,一些树可能会因为不适合这个位置的土壤而损失观赏价值。
教主最喜欢 3 种树,这 3 种树的高度分别为 10,20,30。教主希望这一圈树种得有层次感,所以任何一个位置的树要比它相邻的两棵树的高度都高或者都低,并且在此条件下,教主想要你设计出一套方案,使得观赏价值之和最高。
输入格式
第一行为一个正整数 n,表示需要种的树的棵树。
接下来 n 行,每行 3 个不超过 10000 的正整数 ai,bi,ci,按顺时针顺序表示了第 i 个位置种高度为 10,20,30 的树能获得的观赏价值。
第 i 个位置的树与第 i+1 个位置的树相邻,特别地,第 1 个位置的树与第 n 个位置的树相邻。
输出格式
一个正整数,为最大的观赏价值和。
输入输出样例
输入 #1复制
4 1 3 2 3 1 2 3 1 2 3 1 2
输出 #1复制
11
说明/提示
【样例说明】。
第 1 至 n 个位置分别种上高度为 20,10,30,10 的树,价值最高。
【数据规模与约定】。
- 对于 20% 的数据,有 n≤10;
- 对于 40% 的数据,有 n≤100;
- 对于 60% 的数据,有 n≤1000;
- 对于 100% 的数据,有 4≤n≤105,并保证 n 一定为偶数。
显然的简单线性dp啊。。要那么多维干嘛?一个dp[i][1..4]就轻松过掉
首先我们需要明确目前的状态。。题目要求简谐运动一上一下。状态一共就两种(上&下):
10 -> 20/30; 20 -> 30; 30 -> 10/20; 20 -> 10;
这里我们是不是察觉到了些许的不对劲?没错!就是10 20 10 & 30 20 30 这两种情况是固定的。。所以我们对于1...n枚举4种情况就ok了
但是这样10行代码过不掉只能解决一条链。。题目要求环,而且这个环是会对相邻的元素产生贡献,所以我们需要预处理一下起始位置4种情况。最后记录答案也需要处理。然后我们就完美的过掉了这个题
//好久没写过代码和题解了。。debuged 1 hour
#include<bits/stdc++.h>
using namespace std;
const int N = 100000+5;
const int inf = 1e9;
int n, ans;
int dp[N][5]; // 1: 10 20/30; 2: 10 20 10; 3: 30 20 30; 4: 30 10/20;
int v[N][4]; // 1: 10; 2: 20; 3: 30;
int main()
{
cin>>n;
for(int i = 1; i <= n; i++)
scanf("%d%d%d", &v[i][1], &v[i][2], &v[i][3]);
for(int j = 1; j <= 4; j++) {
memset(dp, 0, sizeof dp);
for(int i = 1; i <= 4; i++)
dp[1][i] = -inf;
if(j == 1) dp[1][j] = v[1][1];
if(j == 2) dp[1][j] = v[1][2];
if(j == 3) dp[1][j] = v[1][2];
if(j == 4) dp[1][j] = v[1][3];
for(int i = 2; i <= n; i++) {
dp[i][1] = max(dp[i-1][2], dp[i-1][4]) + v[i][1];
dp[i][2] = dp[i-1][1] + v[i][2];
dp[i][3] = dp[i-1][4] + v[i][2];
dp[i][4] = max(dp[i-1][1], dp[i-1][3]) + v[i][3];
}
if(j == 1) ans = max(dp[n][2], max(ans, dp[n][4]));
if(j == 2) ans = max(ans, dp[n][1]);
if(j == 3) ans = max(ans, dp[n][4]);
if(j == 4) ans = max(dp[n][1], max(ans, dp[n][3]));
}
cout<<ans<<endl;
return 0;
}