CF2031D - Penchick and Desert Rabbit

CF2031D - Penchick and Desert Rabbit

思路

妙妙妙妙秒极了的一道思维题。

发现 \(i\) 左侧能跳到的都高于它,右侧能跳到的都低于它,考虑如何利用这个性质。

\(f_i\) 表示 \(1 \sim i\) 的最大高度,\(g_i\) 表示 \(i \sim n\) 的最小高度,对应位置分别记为 \(x, y\)

思考有哪些途径可以更新 \(i\) 的答案。

一种是可以直接跳到 \(f_i\)

另一种是借助右侧的某个点 \(j\) 跳到更高的位置,例如当前在 \(3,\) 局势是 \(7 \ 3 \dots 10\ 2\),最优的走法是 \(3 \to 2 \to 10\)。发现这还不够,还有可能是 \(7 \ 3 \dots 10 \ 4\),最优的走法是 \(3 \to 7 \to 10 \to 4\)。先往前跳一步,再往后跳更低的,再跳到更高的位置。

所以总结一下借助右侧点更优的条件,容易发现是 \(f_i \gt g_{i + 1}\),实际上这也是充要的,因为 \(a_x \gt a_y\),我们可以通过 \(i \to x \to y \to ?\) 跳到不劣于 \(x\) 的位置。所以 \(i\) 跳到 \(j\) 一定不劣。

整理一下思路:

\[ans_i = \begin{cases}f_i & f_i \le g_{i + 1} \\ans_{i + 1} & f_i \gt g_{i +1} \end{cases} \]

时间复杂度 \(O(\sum n)\)

#include<bits/stdc++.h>
#define F(i,l,r) for(int i(l);i<=(r);++i)
#define G(i,r,l) for(int i(r);i>=(l);--i)
using namespace std;
using ll = long long;
const int N = 5e5 + 5;
const int inf = 0x3f3f3f3f;
int n, T;
int f[N], g[N], a[N], ans[N];
signed main(){
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	cin >> T;
	while(T --){
		cin >> n;
		F(i, 1, n) cin >> a[i];
		F(i, 1, n) f[i] = max(f[i - 1], a[i]);
		g[n] = a[n]; G(i, n - 1, 1) g[i] = min(g[i + 1], a[i]);
		ans[n] = f[n];
		G(i, n - 1, 1){
			if(f[i] > g[i + 1]) ans[i] = ans[i + 1];
			else ans[i] = f[i];
		}
		F(i, 1, n) cout << ans[i] << ' ';
		cout << '\n';
	}
	return fflush(0), 0;
}

总结

赛时有想过记录前缀 \(\max\) 和后缀 \(\min\),也想过 \(3 \ 10 \ 2\) 这种情况,但是没有想过 \(7 \ 3 \ 10 \ 4\) 这种情况(借助右侧点之前还要先借助一下左侧点)。还有一点是没有去观察哪些位置只能往前或往后跳(虽然这是显然的),以上两点这可能是没能成功运用 \(f\)\(g\) 的主要原因。

继续锻炼自己的能力!从特殊情况入手!充分挖掘好的样例!

posted @ 2024-11-29 08:35  superl61  阅读(47)  评论(0)    收藏  举报