[Gym101653Q]Number Game
题目大意:
(T) 组数据。给定一个 (1sim n) 的全排列,Alice 和 Bob 轮流取数。一个数能被取走,当且仅当这个数紧邻两侧没有比它大的数。取走 (1) 的人获胜。两人都按最优策略进行游戏。
(Tle 100; nle 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),我们可进行如下分类讨论(为使表达简练,此处匹配到第一个条件则停止匹配后续条件):
- (p = 1):最后留下“右坡”共 (ell_r) 个数,游戏总步数为 (n - ell_r);
- (p = n):最后留下“左坡”共 (ell_l) 个数,游戏总步数为 (n - ell_l);
- (ell_l = 0 vee ell_r = 0):由于 (1) 受至少一侧的“上坡”所支配,若两人都按最优策略进行游戏,(1) 一定会在“上坡”取完后,成为整个游戏最后被取走的数,故总步数为 (n);
- (ell_lmod 2 eell_rmod 2):作为先手,Alice 可以任选一边开始游戏,使另一边剩下,总会有一种办法使得总步数为奇数,故赢家一定是 Alice;
- (ell_lmod 2 = ell_rmod 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");
}
}