Codeforces Round #706 (Div. 2) D - Let‘s Go Hiking(思维)

传送门


题目大意

给出一个 1 − n 1-n 1n的排列 p p p A A A B B B玩游戏,一开始两个人各选择一个下标 n n n,规定 A A A先选且先走, A A A只能左边或者右边相邻位置(若存在)且其值小于 A A A当前位置的值; B B B只能左边或者右边相邻位置(若存在)且其值大于 B B B当前位置的值。而且若相邻位置就是对方当前的数字则不能走。给定序列求出哪些位置可以使 A A A获胜。

解题思路

将每段先递增后递减的序列看做“山峰”,那么 A A A需要下山, B B B需要上山,然后我们观察序列不难发现:

  • A A A一定从山顶出发,因为若从山腰出发只能走一个方向, B B B直接在下面“截胡”就GG了。

  • A A A不从“最高峰”(单侧递增/减最长的峰顶)出发,那么 B B B可以选择从“最高峰”的山脚上山,显然 B B B必胜。

  • 若最高峰两侧的长度不等,那么 B B B一定可以选择一个最长侧的一个位置使得其长度长于另一侧且为偶数;否则就是两侧长度相等,两边 A A A能下的最远位置相等,因为 A A A先手所以 A A A如果走不含有 B B B的一侧必败,所以这时 A A A只能硬着头皮走,也就是说当且仅当左右两侧长度相等且为奇数 A A A才会必胜,答案要么是0要么是1。

有一个极容易漏掉的情况就是必胜点如果有多个,那么 B B B不走相同的山即必胜。

//
// Created by Happig on 2021/3/14.
//
#include <bits/stdc++.h>
#include <unordered_map>

using namespace std;
#define ENDL "\n"
#define lowbit(x) (x & (-x))
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<double, double> pdd;
const double eps = 1e-8;
const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;
const double dinf = 1e300;
const ll INF = 1e18;
const int Mod = 1e9 + 7;
const int maxn = 2e5 + 10;

int a[maxn], L[maxn], R[maxn];

int main() {
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        L[i] = R[i] = i;
    }
    for (int i = 1; i < n; i++) {
        if (L[i] != i || a[i + 1] < a[i]) continue;
        while (i < n && a[i + 1] > a[i]) {
            L[i + 1] = L[i];
            i++;
        }
    }
    for (int i = n; i > 1; i--) {
        if (R[i] != i || a[i - 1] < a[i]) continue;
        while (i > 1 && a[i - 1] > a[i]) {
            R[i - 1] = R[i];
            i--;
        }
    }
    int ans = 0, pos = 0, cnt = 0;
    for (int i = 1, l, r; i <= n; i++) {
        l = i - L[i] + 1, r = R[i] - i + 1;
        if (l == 1 || r == 1) continue;
        if (max(l, r) > ans) {
            pos = i;
            ans = max(l, r);
        }
    }
    for (int i = 1, l, r; i <= n; i++) {
        l = i - L[i] + 1, r = R[i] - i + 1;
        if (ans == max(l, r)) cnt++;
    }
    if (!pos) cout << 0 << ENDL;
    else {
        bool ok = 0;
        int l = pos - L[pos] + 1, r = R[pos] - pos + 1;
        if (l == r && (l & 1)) ok = 1;
        if (cnt > 1) ok = 0;
        if (ok) cout << 1 << ENDL;
        else cout << 0 << ENDL;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值