来源是ipsc2006的Kruskal

想了挺久,应该是博弈这一块还不太熟。

一个显然的想法是对每个数找最近素数,然后做。

lowpm(x)表示x-(不小于x的最大素数)

特判了其他情况,只剩下n>=2,每个lowpm(x)>=(k+1),我们认为lowpm(x)为这堆石子的个数。转化为一个类似取石子模型(巴什博奕(Bash Game))。

一个很好的性质是谁取完之后如果一堆的个数<=k,那么他就输了。于是把每堆减去k+1,即转化为谁取完谁赢的经典模型,然后按Multi-SG做(关于Multi-SG可以看http://wenku.baidu.com/view/1716d543a8956bec0975e3f4.html)。

 

Bug有两处

1.特判时没有注意和正常情况的差别,导致(lowpm(x-1)+1)%(m+1)!=0写成了(lowpm(x))%(m+1)!=0

2.没读玩直接break。。。

还是要加油!

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdio>
using namespace std;
typedef long long LL;
#define rep(i,n) for (LL i=1;i<=n;i++)
#define repb(i,b,n) for (LL i=b,n__=n;i<=n__;i++)
 
const LL mN=210,primup=(1<<16);
 
LL a[mN];
LL sa;
LL pm[primup],tpm=0;
LL n,m;
LL lowpm(LL x)
{
    LL now=x;
    bool can;
    while (1)
    {
        can=true;
        for (LL i=1;i<=tpm;i++)
            if (pm[i]*pm[i]<=now)
            {
                if (pm[i]==now)
                    break;
                else
                    if (now%pm[i]==0)
                    {
                        can=false;
                        break;
                    }
            }
            else
                break;
        if (can)
            return x-now;
        now--;
    }
//  while (1)
//  {
//      x=(2*x+1)/2;
//  }
    return 0;
}
void outans(bool x)
{
    if (x)
        cout<<"YES"<<endl;
    else
        cout<<"NO"<<endl;
}
int main()
{
     
    LL ta;
    repb(i,2,primup)
    {
        bool can=true;
        repb(j,2,LL(sqrt(i)+2))
            if (j!=i && i%j==0)
            {
                can=false;
                break;
            }
        if (can)
        {
            pm[++tpm]=i;
        }
    }
    cin>>ta;
    rep(tz,ta)
    {
        cin>>n>>m;
        sa=0;
        bool rev=0;
        if (n==1)
        {
            LL x;
            cin>>x;
            if (x>2 && (lowpm(x-1)+1)%(m+1)!=0)
            {
 
                outans(1);
            }
            else
                outans(0);
            continue;
        }
        bool nodo=false;
        rep(i,n)
        {
            LL x;
            cin>>x;
            if (nodo)
                continue;
            if (x==1)
                rev=!rev;
            else
            {
                a[++sa]=lowpm(x);
                if (a[sa]==0)
                {
                    nodo=true;
                    outans(1);
                   // break;
                }
            }
        }
        if (!nodo)
        {
            LL xo=0;
            rep(i,sa)
            {
                if (a[i]<=m)
                {
                    nodo=true;
                    outans(1);
                    break;
                }
                a[i]-=(m+1);
                xo^=(a[i]%(m+1));
            }
            if (!nodo)
            {
                outans(((rev?1:0) ^ xo)>0);
            }
        }
 
    }
    return 0;
}