[Gym101653Q]Number Game

[Gym101653Q]Number Game

题目大意:

\(T\) 组数据。给定一个 \(1\sim n\) 的全排列,Alice 和 Bob 轮流取数。一个数能被取走,当且仅当这个数紧邻两侧没有比它大的数。取走 \(1\) 的人获胜。两人都按最优策略进行游戏。

\(T\le 100; n\le 100\)

思路:

\(1\) 紧邻两侧仅剩一个数时,Alice 和 Bob 肯定都不愿主动取走这个数(“山峰”),因为这样一来,就能让对方把 \(1\) 取走,然后自己就输了。

有题意得 Alice 和 Bob 都聪明绝顶,为了避免陷入这样的绝境,他们肯定会想方设法先取走别的数。直到不得不面对这一绝境时,输家取走“山峰”,而赢家则将 \(1\) 取走。

此时,剩下的数只有受“山峰”支配的数,在原数列中具体体现为从山峰出发,往 \(1\) 反方向延伸的一段“下坡”。设“坡长”为游戏结束后剩余数的个数,亦即排除山峰以后“下坡”的长度,设其为 \(\ell\),那么游戏进行的总步数为 \(n - \ell\)。显然,若 \((n - \ell) \mod 2 = 1\) 则 Alice 胜,否则 Bob 胜。

\(1\) 在两端时,“下坡”是唯一的(“坡长”可以为 \(0\));但是当它在中间时,则会在两侧各形成一段“下坡”。不妨设 \(1\) 的位置为 \(p\),左边的“坡长”为 \(\ell_l\),右边的为 \(\ell_r\),我们可进行如下分类讨论(为使表达简练,此处匹配到第一个条件则停止匹配后续条件):

  1. \(p = 1\):最后留下“右坡”共 \(\ell_r\) 个数,游戏总步数为 \(n - \ell_r\)
  2. \(p = n\):最后留下“左坡”共 \(\ell_l\) 个数,游戏总步数为 \(n - \ell_l\)
  3. \(\ell_l = 0 \vee \ell_r = 0\):由于 \(1\) 受至少一侧的“上坡”所支配,若两人都按最优策略进行游戏,\(1\) 一定会在“上坡”取完后,成为整个游戏最后被取走的数,故总步数为 \(n\)
  4. \(\ell_l\mod 2\ne\ell_r\mod 2\):作为先手,Alice 可以任选一边开始游戏,使另一边剩下,总会有一种办法使得总步数为奇数,故赢家一定是 Alice;
  5. \(\ell_l\mod 2 = \ell_r\mod 2\):无论 Alice 从哪边开始游戏,总步数的奇偶性都相同,结局都是一样的,此时只能随便选一边,然后听天由命。

最后根据游戏总步数的奇偶性判断胜负即可。

时间复杂度 \(\mathcal O(n)\)

源代码:

#include<cstdio>
#include<cctype>
#include<algorithm>
inline int getint() {
	char ch;
	while(!isdigit(ch=getchar()));
	int x=ch^'0';
	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
	return x;
}
constexpr int N=101;
int a[N];
int main() {
	for(int T=getint();T;T--) {
		const int n=getint();
		for(int i=1;i<=n;i++) a[i]=getint();
		const int p=std::find(&a[1],&a[n]+1,1)-a;
		int len1=0,len2=0;
		for(int i=p-2;i>=1&&a[i]<a[i+1];i--) len1++;
		for(int i=p+2;i<=n&&a[i-1]>a[i];i++) len2++;
		int take=0;
		if(p==1) {
			take=n-len2;
		} else if(p==n) {
			take=n-len1;
		} else if(len1==0||len2==0) {
			take=n;
		} else if(len1%2!=len2%2) {
			take=n-((n-len1)%2?len1:len2);
		} else {
			take=n-len1;
		}
		puts(take%2?"Alice":"Bob");
	}
}
posted @ 2021-10-20 00:21  skylee03  阅读(63)  评论(0编辑  收藏  举报