花园改造 题解
题目id:9989
题目描述
小\(X\)开始改造她的环形的花园了,具体来说她要在花园的环上种满\(n\)棵树。她现在有\(3\)种树:种子、小树苗和大树。每个位置上种不同的树会产生不同的满意度,具体来说在第\(i\)个位置,种种子会产生\(a_i\)的满意度,种小树苗会产生\(b_i\)的满意度,种大树会产生\(c_i\)的满意度。为了获取最大的满意度之和,她只要在每个位置种上该位置满意度最大的树就行了。但是附近的巫婆告诉她,种子的边上(距离为\(1\)的相邻,下同)不能有种子,大树的边上不能有大树,小树苗的边上要么都是种子、要么都是大树,不然花园所有树不久就会枯死。小\(X\)当然不允许这种事情发生,所以她就向小\(Q\)求助了。可惜的是小\(Q\)也不知道应该怎么做,请聪明的你帮帮他吧。
注意哦,花园是环形的,也就是说第1个位置的边上不只是第2个位置,还有第\(n\)个位置;第\(n\)个位置的边上不只是第\(n-1\)个位置,还有第\(1\)个位置。
解题思路
一眼\(dp\)题。
设\(dp_{i,j,k}\)为在第\(i\)个位置用了第\(j\)种树(种子\(/\)小树苗\(/\)大树)比旁边位置高\(/\)矮\((k\)用\(0\)或\(1\)表示,\(0\)表示矮,\(1\)表示高\()\)
四个状态转移方程式分别为:
dp[i][0][0]=max(dp[i-1][1][1],dp[i-1][2][1])+a[i][0];
dp[i][1][0]=dp[i-1][2][1]+a[i][1];
dp[i][1][1]=dp[i-1][0][0]+a[i][1];
dp[i][2][1]=max(dp[i-1][1][0],dp[i-1][0][0])+a[i][2];
\(ans\)对\(dp_{n,i,0}\)和\(dp_{n,i,1}\)取\(\max\)即可。
AC Code
#include<bits/stdc++.h>
#define N 1000007
#define INF 1e18
#define MOD 998244353
#define LL long long
#define pb push_back
#define lb long double
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define IOS ios::sync_with_stdio(0),cin.tie(nullptr),cout.tie(nullptr)
using namespace std;
LL n,a[N][3],dp[N][4][2],ans;
int main()
{
IOS;
cin>>n;
for(int i=1;i<=n;++i)
for(int j=0;j<3;++j)
cin>>a[i][j];
for(LL j=0;j<3;++j)
{
for(LL i=0;i<3;++i)
for(LL k=0;k<2;++k)dp[1][i][k]=0;
dp[1][j][0]=dp[1][j][1]=a[1][j];
for(int i=2;i<=n;++i)
{
dp[i][0][0]=max(dp[i-1][1][1],dp[i-1][2][1])+a[i][0];
dp[i][1][0]=dp[i-1][2][1]+a[i][1];
dp[i][1][1]=dp[i-1][0][0]+a[i][1];
dp[i][2][1]=max(dp[i-1][1][0],dp[i-1][0][0])+a[i][2];
}
for(int i=0;i<j;++i)ans=max(ans,dp[n][i][0]);
for(int i=2;i>j;--i)ans=max(ans,dp[n][i][1]);
}
cout<<ans;
return 0;
}