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