题解:CF794E Choosing Carrot
posted on 2024-11-26 11:59:12 | under | source
先不考虑 A 提前拿走数。
注意到后手比较厉害,可以做先手相反的操作使得每一轮恰好两侧的数被扔掉。
记 \(mid=\frac{l+r}2\)。当 \(2\mid n\) 时,B 可以使得答案 \(\le \max(a_{mid},a_{mid+1})\)。A 可以一开始拿走左侧的然后与 B 做相反操作然后得到 \(a_{mid+1}\),\(a_{mid}\) 同理。故答案为 \(\max(a_{mid},a_{mid+1})\)。
上述讨论在 B 先手时是对偶情况,可以推出当 \(2\nmid n\) 时答案是 \(\max(\min(a_{mid-1},a_{mid}),\min(a_{mid},a_{mid+1}))\)。注意 \(n=1\) 的特殊情况。
加入修改,那么就是对所有 \(n-k\) 大小的区间取个 \(\max\),显然有个 \(st\) 表做法,考虑 \(mid\) 的下标范围即可。
但是还有更简单的线性做法,注意到将区间两侧同时缩短 \(1\) 答案不变,那么可以递推,\(k\) 必然可以继承 \(k-2\) 的所有情况(每个区间缩短两侧),然后只需加入两侧的区间答案即可。
复杂度 \(O(n)\)。
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 3e5 + 5;
int n, a[N], ans[N], mx;
inline int get(int l, int r){
int mid = (l + r) >> 1;
if((r - l) & 1) return max(a[mid], a[mid + 1]);
return max(min(a[mid - 1], a[mid]), min(a[mid], a[mid + 1]));
}
signed main(){
cin >> n;
for(int i = 1; i <= n; ++i) scanf("%lld", &a[i]), mx = max(mx, a[i]);
ans[0] = get(1, n);
ans[1] = max(get(1, n - 1), get(2, n));
for(int i = 2; i < n - 1; ++i) ans[i] = max(ans[i - 2], max(get(1, n - i), get(i + 1, n)));
for(int i = 0; i < n; ++i) printf("%lld ", (i < (n - 1)) ? ans[i] : mx);
return 0;
}

浙公网安备 33010602011771号