[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;
}

浙公网安备 33010602011771号