题解:CF2133D Chicken Jockey

· · 题解

Solution

首先考虑最简单的情况,每次只杀栈底的怪物:

此时的答案是 \textrm{base} = h_1 + \sum_{i = 2} ^{n} \max(0, h_i - 1)

然后我们考虑提前杀掉第 i(i \leq n - 1) 只怪的收益。

则净收益为 \Delta_i = \max(0, h_{i + 1} - 1) - \max(0, h _{i + 1} - i) - 1

很自然地,我们想到 dp。但如果直接 dp 的话是有后效性的。多个位置一起提前杀,收益显然不是直接相加,而是会彼此影响。

这时候注意到一个结论:两个相邻的位置不能都被提前杀掉,否则一定不优。

证明:我们假设把 ii + 1 都提前杀掉(记作 \texttt{A}),证明其一定劣于只提前杀 i + 1(记作 \texttt{B})。

显然其只会影响到 i, i + 1, i + 2,我们分别来考虑。

综上,\texttt{A}\texttt{B} 多打 12 刀,所以 \texttt{A} 劣于 \texttt{B}

证毕。

v_i = \max(0, \Delta_i),问题转化为:选不相邻的若干位置使得 \sum v_i 最大。

于是就变成了简单 dp!设 \textrm{dp}_{i, 1/0} 表示到 i 为止且选/不选 i 的最大收益。转移是简单的。

\textrm{dp}_{i, 0} = \max(\textrm{dp}_{i - 1, 0}, \textrm{dp}_{i - 1, 1}) \\ \textrm{dp}_{i, 1} = \textrm{dp}_{i - 1, 0} + v_i

最后答案就是 \textrm{base} - \max(\textrm{dp}_{n - 1, 0}, \textrm{dp}_{n - 1, 1})

Code

::::info[在这]

// Problem: D. Chicken Jockey
// Contest: Codeforces - Codeforces Round 1044 (Div. 2)
// URL: https://codeforces.com/contest/2133/problem/D
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long 
#define pii pair<int,int>
#define pb push_back
#define endl '\n'
#define rep(i, a, b) for(int (i) = (a); (i) <= (b); (i) ++)
#define per(i, a, b) for(int (i) = (a); (i) >= (b); (i) --)
#define ls x << 1
#define rs x << 1 | 1

using namespace std;

const int maxn = 2e5 + 5;

int n, h[maxn] ;
int v[maxn] ;
int f[maxn][2] ;

void solve(){
    cin >> n ;
    v[1] = 0 ;
    rep(i, 1, n) f[i][0] = f[i][1] = 0 ;
    rep(i, 1, n) cin >> h[i] ;
    int base = h[1] ;
    rep(i, 2, n) base += max(0ll, h[i] - 1) ;
    rep(i, 2, n - 1) {
        int delta = max(0ll, h[i + 1] - 1) - max(0ll, h[i + 1] - i) - 1 ;
        v[i] = max(0ll, delta) ;
    }
    rep(i, 1, n - 1) {
        f[i][0] = max(f[i - 1][0], f[i - 1][1]) ;
        f[i][1] = f[i - 1][0] + v[i] ;
    }
    cout << base - max(f[n - 1][0], f[n - 1][1]) << endl ;
    return ;
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    int T = 1 ; 
    cin >> T ;
    while(T -- ){
        solve() ;
    }
    return 0 ;
} 

::::