题目
题意概括一下就是:有n张牌,每个人可以从牌顶或牌底抽若干张(至少抽1张),或从牌顶和牌底抽走同样张数,抽中从上往下第x张的输,问先手是否有必胜策略

首先,我们转化一下,设a=x-1,b=n-x,即a为x上面有几张牌,b为下面有几张
当a=b=0时,先手无必胜策略,因为先手只能抽走这一张牌
当a,b其中一个是0,先手有必胜策略,因为先手可以从一端抽牌,只剩一张,后手便必输
当a=b时,先手有必胜策略,先手可以从两端抽走相同张数的牌,只剩一张
剩下的情况,一开始看的时候,还是没有想法,所以我先列了张表:(“√”“×”代表先手是否有必胜策略)
图片说明
只列一半是因为a,b交换是一样的情况,a=b的情况也讨论过了
我们来分析每一个格子里的情况
a=2,b=1时,通过列举每种情况得知先手没有必胜策略
a>2,b=1时,先手可以先在a的一段抽走若干,使变成a=2,b=1情况,所以先手有必胜策略
a>2,b=2时,先手可以先在a的一段抽走若干,使变成a=1,b=2也就是a=2,b=1情况,所以先手有必胜策略
a=4,b=3时,先手可以在两端拿走两张,使变成a=2,b=1情况,所以先手有必胜策略
a=5,b=3时,先手没有必胜策略

至此,大家可能没有发现什么规律,但我们翻转一下表格,都到:
图片说明
至此,我们可以发现一个规律:
每一个格子如果填“√”,当且仅当:

  • 此格向左上方走若干个后走到一个“×”(对应的是从两端抽走相同个数牌)
  • 或向左走若干个后走到一个“×”
  • 或向上走若干个后走到一个“×”(后面两种对应的是从一端收走若干牌)

否则此格为“×”

我们发现,每一行只会有一个“×”,于是用一个数组预处理出所有”ד的位置,此题便完成了
代码(有注释):

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;
const int maxn=3000020;

int a[maxn];

int main() {
    int mx=1;//每一条自左上向右下的链上,行和列编号差值一定,记为mx
    //即当前1~(mx-1)所代表的链都有”ד了
    for(int i=3; i<=3000000; ++i) {
        if(a[i]==0) {//没有填过相当于此行和此列没有出现过”ד,因此向左上找
            a[i]=i+mx; //i+1~i+mx-1都是”√“,i+mx匹配不到”ד,所以为”ד
            if(i+mx<=3000000) a[i+mx]=i; //表格是对称的
            ++mx;//增加一条自左上向右下的链
        }
    }
    int T; scanf("%d", &T);
    while(T--) {
        int n, x; scanf("%d%d", &n, &x);
        if(x-1==0&&n-x==0) printf("ma la se mi no.1!\n");
            else if(x-1==0||n-x==0) printf("yo xi no forever!\n");
                else if(a[x-1]==n-x) printf("ma la se mi no.1!\n");
                    else printf("yo xi no forever!\n");
    }
    return 0;
}