[CF]1495B - Let's Go Hiking

题目链接 https://codeforces.com/contest/1495/problem/B
题意:
给你一个大小为n(n≥2)的排列,青山和达尼尔两人轮流玩游戏。
开始时任选起点 ,选完起点后只能往相邻的格走。
青山先走,要求是她每一步走到的数字都要比前面小 达尼尔正好相反
规定两人不能同时处于同一个点也不能越界 最终谁无法移动了谁就输了。
有多少个起点,在最优策略情况下,能使得青山必胜

分析:
1、如果先手从最左边或最右边开始走,或者选的这个点使得自己只能往一个方向走,先手必败,因为后手只要堵住一个方向就行了。
2、先手只能从最长连续段的一头选为起点,否则的话后手直接从这一最长连续段的另一头走就赢了。
3、如果有多段不在一起的的最长连续段(没有共享同一个峰顶),先手也必败,因为他们都能走len步。(len为最长段的长度)
4、如果这个最长段是偶数 也必败。因为两人都能走len/2步。
5、如果选的点是峰顶 左右两连续段的长度(一升一降)一奇一偶,奇数更大一些,先手必败。
后手踩在(奇数方向)另一端开始的第二个点
(1)如果先手往奇数方向走 则两人都能走(len-1)/2步 但先手不能再移动了。
(2)如果先手往偶走 后手能移动的步数大于等于先手
6、两端都是奇数但不相等
后手也是踩在最长奇数段的另一端的第二个点就稳赢了。
7、只有这个点左右两端都是最长段且长度为奇数才必胜
当这个点只有一个时,才必胜。否则的话跳到分析3。所以就算能先手必胜答案也只是1。
先手必胜策略:按照分析找到点,往后手选的点所在方向走。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <utility>
#include <map>
#include <vector>
#include <queue>
using namespace std;
typedef long long LL;
const int N=1e5+10;
int a[N],up[N],dn[N];//up从左往右连续上升的长度 dn从右往左连续上升的长度
void solve()
{
	int n;cin>>n;
	a[0]=a[n+1]=up[0]=dn[n+1]=0;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		if(a[i]>a[i-1])up[i]=up[i-1]+1;
		else up[i]=1;
	}
	for(int i=n;i>=1;i--)
	{
		if(a[i]>a[i+1])dn[i]=dn[i+1]+1;
		else dn[i]=1;
	}
	int pos,maxn=-1;
	int cnt=0;//最长连续段的个数
	for(int i=1;i<=n;i++)maxn=max(maxn,max(up[i],dn[i]));//最长的一段长是多少
	for(int i=1;i<=n;i++)
	{
		if(up[i]==dn[i]&&up[i]==maxn)cnt++,pos=i;//是峰顶 只计一次
		else if (up[i]==maxn||dn[i]==maxn)cnt++,pos=i;
	}
	if(cnt>1){puts("0");return ;}//对应分析3 
	if(up[pos]==dn[pos]&&up[pos]%2==1)puts("1");
	else puts("0");
}
int main()
{
    cin.tie(0);ios::sync_with_stdio(false);
    int tests=1;
    while(tests--)
    {
    	solve();
    }
     return 0;
}
posted @ 2021-03-14 18:40  liv_vil  阅读(107)  评论(0)    收藏  举报