Codeforces 201C Fragile Bridges 题解 [ 绿 ] [ 线性 DP ] [ 枚举 ]

Fragile Bridges:经典的路径观察题。

考虑路径的形态,不难发现路径可以由起点向左走的一段路与从起点向右走的一段路拼接而成。其中,这两段路里的至少一段需要回到起点

于是考虑从左往右和从右往左分别进行一次 DP,这里以从左往右为例:定义 \(dp_{i,0/1}\) 为考虑前 \(i\) 位,且起点为 \(i\),未回到 / 回到了第 \(i\) 位的最长路径长度,转移是显然的:

  • \(dp_{i,0}=\max(dp_{i-1,0},dp_{i-1,1})+a_i-[a_i\bmod 2=0]\),因为在走完一次桥之后,可以反复走 \(i\) 桥来把桥走断。
  • \(dp_{i,1}=dp_{i-1,1}+a_i-[a_i\bmod 2=1]\),因为要求了折返走,也就是不能走奇数次这个桥。

枚举起点,分三种情况(先左后右、先右后左、走完两边然后回来)统计答案即可。

#include <bits/stdc++.h>
#define fi first
#define se second
#define eb(x) emplace_back(x)
#define pb(x) push_back(x)
#define lc(x) (tr[x].ls)
#define rc(x) (tr[x].rs)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
using pi=pair<int,int>;
const int N=100005;
int n;
ll a[N],predp[2][N],sufdp[2][N],ans;
int main()
{
    //freopen("sample.in","r",stdin);
    //freopen("sample.out","w",stdout);
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin>>n;
    for(int i=1;i<n;i++)cin>>a[i];
    for(int i=1;i<n;i++)
    {
        predp[0][i]=max(predp[1][i-1],predp[0][i-1])+a[i]-(a[i]%2==0);
        if(a[i]>1)predp[1][i]=predp[1][i-1]+a[i]-(a[i]%2==1);
        else predp[1][i]=0;
    }
    for(int i=n-1;i>=1;i--)
    {
        sufdp[0][i]=max(sufdp[1][i+1],sufdp[0][i+1])+a[i]-(a[i]%2==0);
        if(a[i]>1)sufdp[1][i]=sufdp[1][i+1]+a[i]-(a[i]%2==1);
        else sufdp[1][i]=0;    
    }
    for(int i=0;i<n;i++)
    {
        ans=max(ans,predp[0][i]+sufdp[1][i+1]);
        ans=max(ans,predp[1][i]+sufdp[0][i+1]);
        ans=max(ans,predp[1][i]+sufdp[1][i+1]);
    }
    cout<<ans;
    return 0;
}
posted @ 2025-05-03 15:52  KS_Fszha  阅读(6)  评论(0)    收藏  举报