Codeforces Round #706 (Div. 2)-D. Let's Go Hiking 题解
题目传送门
解题思路:
从两个人能够选择的点来看,\(Qingshan\)要走的是上升序列,\(Daniel\)要走的是下降序列。所以如果\(Qingshan\)要取得胜利的话,就必须要在上升序列的顶峰处开始往低处走,并且能比\(Daniel\)走的步数多或者挡住\(Daniel\)的下一步。两个人的最优选项都是走尽可能多次或者可以挡住对方。注意\(Qingshan\)不能从\(1\)或者\(n\)开始走,否则\(Daniel\)选择\(2\)或者\(n-1\)即可获胜。
接下来我们就需要记录下最长上升序列和下降序列的长度\(len\),同时记录一下这样的序列个数\(num\)。并且我们能会发现,\(len\)至少为2,\(num\)至少为1。
假设一开始\(Qingshan\)开始的位置为\(x\),序列开始的位置为\(s\),我们会发现\(Qingshan\)必须要从\(x=s+len-1\)开始走,如果不是的话,\(Daniel\)可以直接选在\(x-1\)处(上升)或者\(x+1\)处(下降),这样\(Qingshan\)就会直接输掉。
如果这样的序列个数大于\(2\),那么\(Qingshan\)一定会输,因为\(Daniel\)可以走\(len\)步,但是\(Qingshan\)最多只能走\(len\)步,并且\(Qingshan\)是先手。
如果只有\(1\)个这样的序列,我们就需要对序列长度的奇偶性进行讨论:
①\(len\)是偶数。由于\(Qingshan\)开始的位置只能是\(s+len-1\),所以\(Daniel\)在这样的情况下总是可以挡住\(Qingshan\)的下一步,比如从\(s\)开始走,所以这种情形下\(Qingshan\)一定是输的。
②\(len\)是奇数。和偶数的情况一样,\(Daniel\)总是可以挡住\(Qingshan\),所以这种情形下\(Qingshan\)一定是输的。
如果有两个这样的序列,我们只需要比较一下上升序列和下降序列的长度,只有上升序列长度等于下降序列长度且长度都为奇数,\(Qingshan\)才能获胜。
总结发现,如果序列长度是偶数的话,直接输出\(0\)即可。
代码:
#include<cstdio>
#include<iostream>
#define _CRT_SECURE_NO_WARNINGS
using namespace std;
const int N = 100005;
int h[N];
int up[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin >> n;
for (int i = 1; i <= n; i++) cin >> h[i];
for (int i = 2; i <= n; i++) up[i] = (h[i] > h[i - 1]) ? 1 : 0;
int len = 0, num = 0;
int l, r;
for (l = 2, r = 2; l <= n; )
{
int st = up[l];
while (r + 1 <= n && st == up[r + 1]) r++;
int tlen = r - l + 2;
if (tlen > len)
{
len = tlen;
num = 1;
}
else if (tlen == len) num++;
l = r = r + 1;
}
if (num != 2 || (len & 1) == 0) cout << 0 << endl;
else
{
int isWin = 0;
for (int i = 3; i <= n; i++)
{
if (up[i - 1] && !up[i])
{
int l = i - 1, r = i;
while (l - 1 >= 1 && up[l - 1]) l--;
while (r + 1 <= n && !up[r + 1]) r++;
if ((r - i + 1)+1 ==len&& (i-1)-(l-1)+1 ==len)
{
isWin = 1;
break;
}
}
}
cout << isWin << endl;
}
return 0;
}