花园改造 题解

题目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;
}
posted @ 2024-08-06 16:51  Firra3500  阅读(26)  评论(1编辑  收藏  举报