https://codeforces.com/contest/1495
B. Let’s Go Hiking
题意:给定一个 n 的排列,两个人轮流操作:第一次时先选一个初始位置放棋子,之后先手可以移动到两边一个比当前位置权值小的位置,后手可以移动到两边一个比当前位置权值大的位置。问先手有几个初始位置可以必胜。
博弈
思路比较直接,但是细节有点多,要考虑全面。
枚举每个位置作为先手的初始位置,分类讨论。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| #include <bits/stdc++.h> #define debug(x) cout << #x << ":\t" << (x) << endl; using namespace std; #define ll long long #define ull unsigned ll const int N = 5e6 + 10; const int INF = 0x3f3f3f3f; const ll inf = 0x3f3f3f3f3f3f3f3f; const ll mod = 1e9 + 7; const ll inv2 = (mod + 1) / 2; int n; int a[N]; int l[N], r[N], mx[N]; multiset<int, greater<int> >st; int main() { scanf("%d", &n); for (int i = 1; i <= n; i++)scanf("%d", &a[i]); l[1] = r[n] = 0; for (int i = 2; i <= n; i++) { if (a[i] > a[i - 1])l[i] = l[i - 1] + 1; else l[i] = 0; } for (int i = n - 1; i >= 1; i--) { if (a[i] > a[i + 1])r[i] = r[i + 1] + 1; else r[i] = 0; } for (int i = 1; i <= n; i++) { mx[i] = max(l[i], r[i]); st.insert(mx[i]); } int ans = 0; bool flg = 0; for (int i = 1; i <= n; i++) { if (min(l[i], r[i]) <= 1)continue; st.erase(st.find(mx[i])); int x = (*st.begin()); if (l[i] % 2 == 0 && r[i] % 2 == 0) { if (mx[i] > x && l[i] == r[i])ans++; } else if (l[i] % 2 == 0 && r[i] % 2 == 1) { if (l[i] > max(x, r[i]) && r[i] > l[i] - 1)ans++; } else if (l[i] % 2 == 1 && r[i] % 2 == 0) { if (r[i] > max(x, l[i]) && l[i] > r[i] - 1)ans++; } st.insert(mx[i]); } printf("%d\n", ans); return 0; }
|