B. Let’s Go Hiking
题意
有一个长度为 n n n 的排列。首先Qingshan选择一个数 a a a ,Daniel选择另一个数 b b b 。
Qingshan先手,每次移动到相邻的数 a ′ ( a ′ < a , a ′ ! = b ) a'(a'<a,a'!=b) a′(a′<a,a′!=b),然后Daniel移动到相邻的数 b ′ ( b ′ > b , b ′ ! = a ) b'(b'>b,b'!=a) b′(b′>b,b′!=a)
问Qingshan初始有多少种选择可以必胜。
题解
- 把这个排列分割成若干单调区间;
- Qingshan选择的数一定在一个最长的单调区间上,否则Daniel可以选择一个更长单调区间的端点;
- 由于是Qingshan先选择且先手,如果只有一个最长的单调区间,Daniel可以后手选择一个位置来保证必胜,如果有大于2个最长的单调区间,那么两个人可以走相同的距离,后手必胜;
- 所以必须两个人选择同一个单调区间的两个端点相互靠近,并且区间的长度为奇数可以保证必胜;
- 答案只有可能为 0/1。
代码
#pragma region
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <vector>
using namespace std;
typedef long long ll;
#define rep(i, a, n) for (int i = a; i <= n; ++i)
#define tr t[root]
#define lson t[root << 1]
#define rson t[root << 1 | 1]
#pragma endregion
const int maxn = 2e5 + 5;
int n;
ll a[maxn];
vector<pair<ll, ll>> id;
bool check() {
if (id.size() != 2) return 0;
int l1 = id[0].first, r1 = id[0].second;
int l2 = id[1].first, r2 = id[1].second;
return r1 == l2 && a[r1] > a[l1] && a[l2] > a[r2] && (r1 - l1) % 2 == 0;
}
int main() {
scanf("%d", &n);
rep(i, 1, n) scanf("%lld", &a[i]);
int maxx = 0;
for (int l = 1, r = 2; r <= n; l = r, r = r + 1) {
while (r + 1 <= n && (a[r + 1] - a[r]) * (a[r] - a[l]) > 0) ++r;
if (r - l + 1 >= maxx) {
if (r - l + 1 > maxx) id.clear(), maxx = r - l + 1;
id.push_back({l, r});
}
}
puts(check() ? "1" : "0");
}