专栏文章

题解:CF2133D Chicken Jockey

CF2133D题解参与者 3已保存评论 2

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
2 条
当前快照
1 份
快照标识符
@mio4upp8
此快照首次捕获于
2025/12/02 13:23
3 个月前
此快照最后确认于
2025/12/02 13:23
3 个月前
查看原文

Solution

首先考虑最简单的情况,每次只杀栈底的怪物:
  • 对于第 11 个怪:需要 h1h_1 刀。
  • 对于第 i(i2)i(i \geq 2) 个怪:在第 i1i - 1 个怪死后,它会掉 11 点坠落伤害,于是就需要 max(0,hi1)\max(0, h_i - 1) 刀。
此时的答案是 base=h1+i=2nmax(0,hi1)\textrm{base} = h_1 + \sum_{i = 2} ^{n} \max(0, h_i - 1)
然后我们考虑提前杀掉第 i(in1)i(i \leq n - 1) 只怪的收益。
  • 对于第 ii 只怪:本来需要 hi1h_i - 1 刀,现在需要 hih_i 刀,收益为 1-1
  • 对于第 i+1i + 1 只怪:本来需要 max(0,hi+11)\max(0, h_{i + 1} - 1) 刀,现在需要 max(0,hi+1i)\max(0, h_{i + 1} - i) 刀,收益为两者相减。
则净收益为 Δi=max(0,hi+11)max(0,hi+1i)1\Delta_i = \max(0, h_{i + 1} - 1) - \max(0, h _{i + 1} - i) - 1
很自然地,我们想到 dp。但如果直接 dp 的话是有后效性的。多个位置一起提前杀,收益显然不是直接相加,而是会彼此影响。
这时候注意到一个结论:两个相邻的位置不能都被提前杀掉,否则一定不优。
证明:我们假设把 iii+1i + 1 都提前杀掉(记作 A\texttt{A}),证明其一定劣于只提前杀 i+1i + 1(记作 B\texttt{B})。
显然其只会影响到 i,i+1,i+2i, i + 1, i + 2,我们分别来考虑。
  • 对于 iiA\texttt{A} 需要 hih_i 刀,B\texttt{B} 现在需要 hi1h_i - 1 刀,A\texttt{A}B\texttt{B} 多打 11 刀。
  • 对于 i+1i + 1A\texttt{A}B\texttt{B} 相同,都是 hi+1h_{i + 1} 刀。
  • 对于 i+2i + 2:对于 A\texttt{A},由于 ii 已经被杀掉了,所以杀 i+1i + 1i+2i + 2 下面有 ii 个怪;对于 B\texttt{B},杀 i+1i + 1i+2i + 2 下面有 i+1i + 1 个怪。
    A\texttt{A}B\texttt{B} 多打的刀数为 max(0,hi+2i)max(0,hi+2(i+1))\max(0, h_{i + 2} - i) - \max(0, h_{i + 2} - (i + 1)) {0,1}\in \{0, 1\}
综上,A\texttt{A}B\texttt{B} 多打 1122 刀,所以 A\texttt{A} 劣于 B\texttt{B}
证毕。
vi=max(0,Δi)v_i = \max(0, \Delta_i),问题转化为:选不相邻的若干位置使得 vi\sum v_i 最大。
于是就变成了简单 dp!设 dpi,1/0\textrm{dp}_{i, 1/0} 表示到 ii 为止且选/不选 ii 的最大收益。转移是简单的。
dpi,0=max(dpi1,0,dpi1,1)dpi,1=dpi1,0+vi\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
最后答案就是 basemax(dpn1,0,dpn1,1)\textrm{base} - \max(\textrm{dp}_{n - 1, 0}, \textrm{dp}_{n - 1, 1})

Code

在这CPP
// 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 ;
} 

评论

2 条评论,欢迎与作者交流。

正在加载评论...