Codeforces 706(Div. 2) D. Let‘s Go Hiking

Let’s Go Hiking
题目链接

题目大意

Qingshan和Daniel在玩一个游戏。(以下简称Q和D)
首先在纸上写出一个排列 p p p
最初,Q先选择一个数 x x x ,然后D选择另一个数 y y y y ≠ x y\neq x y=x 。可以理解为最初时刻,Q在数列的第 x x x 个位置上,D在第 y y y 个位置上。
游戏将从Q开始,以Q、D、Q、D……的顺序依次按照如下规则进行:

  • 如果是Q的轮次,Q可以向当前位置左边或右边移动,且需要满足移动后的位置的数比原先的数且D不在该位置;
  • 如果是D的轮次,D可以向当前位置左边或右边移动,且需要满足移动后的位置的数比原先的数且Q不在该位置;

如果有一个人无法继续走下去,那么他就输了。假设Q和D每个人都会选择最优方案去执行。
现在给出一个排列,请问Q最先选择的数 x x x有几个能够使他获胜。

样例输入

5
1 2 5 4 3

样例输出

1

样例解释

  • x = 1 x=1 x=1 ,则 y y y 不管选什么数,Q必败;
  • x = 2 x=2 x=2 ,则 y = 1 y=1 y=1 ,Q必败;
  • x = 3 x=3 x=3 ,则 y y y 不管选什么数,Q必胜;
  • x = 4 x=4 x=4 ,则 y = 5 y=5 y=5 ,Q必败;
  • x = 5 x=5 x=5 ,则 y y y 不管选什么数,Q必败。

思路

首先假定几个概念,如果一个数两侧的数都比该数小,那么称作山峰,如果一个数两侧的数都比该数小,那么称作山谷,其余位置为山坡。

  • 首先,若Q选择山谷的位置,两侧数都比该数大,那么Q在第一轮就输了;
  • 由于D是在Q写出 x x x 后决定 y y y 的取值,如果Q选择山坡的位置, y y y 只需要选择比该数小的数的下标,就可以使Q第一轮输掉比赛;

综上两种情况,所以Q必须选择山峰位置的数,才有可能赢。下面再来讨论一下Q选择山峰后的情况。另外,该数列必定存在一条最长的山坡(即 m a x max max(最长上升子区间的长度,最长下降子区间的长度)),记该长度为 l e n len len

  • 若选择的山峰两侧的山坡长度均小于 l e n len len,那么D只需要选择最长山坡的山谷处的位置,即可保证Q必输;
  • 若选择的山峰两侧的山坡至少有一侧长度与 l e n len len相等,则此时再分情况进行讨论,结果就很清晰了

(假设山坡长的一侧为 b i g big big,短的一侧为 s m a l l small small

下列讨论为分奇偶讨论,可以自己画一下然后模拟以下过程,会更能理解。

  • b i g > s m a l l big>small big>small,假设 b i g = 2 a , s m a l l = 2 b big=2a,small=2b big=2a,small=2b,当D选择 b i g big big侧从山峰往下的 2 b 2b 2b位置(即与 s m a l l small small侧山谷对称的位置)时,Q必败;
  • b i g > s m a l l big>small big>small,假设 b i g = 2 a + 1 , s m a l l = 2 b big=2a+1,small=2b big=2a+1,small=2b,当D选择 b i g big big侧从山峰往下的 2 b 2b 2b位置(即与 s m a l l small small侧山谷对称的位置)时,Q必败;
  • b i g > s m a l l big>small big>small,假设 b i g = 2 a , s m a l l = 2 b + 1 big=2a,small=2b+1 big=2a,small=2b+1,当D选择 b i g big big侧从山峰往下的 2 a 2a 2a位置(即 b i g big big侧山谷位置)时,Q必败;
  • b i g > s m a l l big>small big>small,假设 b i g = 2 a + 1 , s m a l l = 2 b + 1 big=2a+1,small=2b+1 big=2a+1,small=2b+1,当D选择 b i g big big侧从山峰往下的 2 b + 2 2b+2 2b+2位置时,Q必败。

此时可以发现,只剩下一种情况:

  • b i g = = s m a l l big==small big==small,只有当 b i g big big为奇数,且长度为 l e n ( = b i g = s m a l l ) len(=big=small) len(=big=small)的山坡小于等于两个时,才可能取胜。

综上讨论后,答案只有可能是0或1。

参考代码

#include <bits/stdc++.h>
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
int a[100010];
int l[100010],r[100010]; 
map<int,int> mp;
int main(){
	IO;
	int n;
	cin>>n;	
	int cnt=0;
	a[0]=0;
	for (int i=1;i<=n;i++){
		cin>>a[i];
		if (a[i]>a[i-1]) cnt++;
		else{
			if (cnt!=1) l[i-1]=cnt;
			cnt=1;
		}
	}
	if (cnt!=1) l[n]=cnt;
	cnt=0;
	a[n+1]=0;
	for (int i=n;i>=1;i--){
		if (a[i]>a[i+1]) cnt++;
		else{
			if (cnt!=1) r[i+1]=cnt;
			cnt=1;
		}
	}
	if (cnt!=1) r[1]=cnt;
	int len=0;
	for (int i=1;i<=n;i++) {
		len=max(len,max(l[i],r[i]));
		mp[l[i]]++;
		mp[r[i]]++;
	}
	
	int ans=0;
	for (int i=1;i<=n;i++){
		if (l[i]==0||r[i]==0) continue;
		int big=max(l[i],r[i]),small=min(l[i],r[i]);
		if (big<len) continue;
		if (big==small){
			if (mp[big]>2) continue;
			if (big%2==1) ans++;
			continue;
		}	
	}
	cout<<ans<<endl;
	return 0;
}
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值