列表

详情


NC19994. [HAOI2015]数组游戏

描述

有一个长度为N的数组,甲乙两人在上面进行这样一个游戏:
首先,数组上有一些格子是白的,有一些是黑的。然 后两人轮流进行操作。每次操作选择一个白色的格子,假设它的下标为x。
接着,选择一个大小在1~n/x之间的整数 k,然后将下标为x、2x、...、kx的格子都进行颜色翻转。不能操作的人输。
现在甲(先手)有一些询问。每次他会给你一个数组的初始状态,你要求出对于这种初始状态他是否有必胜策略。

输入描述

接下来2*K行,每两行表示一次询问。
在这两行中,第一行一个正整数W,表示数组中有多少个格子是白色的,第二行则有W个1~N之间的正整数,表示白色格子的对应下标。

输出描述

对于每个询问,若先手必胜输出"Yes",否则输出"No"。答案之间用换行隔开

示例1

输入:

3
2
2
1 2
2
2 3

输出:

Yes
No

说明:

【样例解释】
在第一个询问中,甲选择点1,然后将格子1*1和2*1翻过来即可。
第二个询问中,无论甲选择哪个点,都只能翻掉一个格子。乙只需
翻掉另一个格子就行了。

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0)(g++7.5.0) 解法, 执行用时: 601ms, 内存消耗: 1132K, 提交时间: 2023-01-28 15:37:24

#include<iostream>
#include <bits/stdc++.h>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<climits>
#include<ctime>
using namespace std;
template<typename T>bool chkmax(T &_,T __){return _<__ ? (_=__,1) : 0;}
template<typename T>bool chkmin(T &_,T __){return _>__ ? (_=__,1) : 0;}
#define REP(i,a,b) for(register int i=a;i<=b;++i)
#define DREP(i,a,b) for(register int i=a;i>=b;--i)
#define MREP(i,x) for(register int i=beg[x];i;i=E[i].last)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define inf INT_MAX
const int maxn=1e9+10;
const int maxm=100+10;
int n,q,m,a[maxm],SG[maxm*maxm],L[maxn/10000],R[maxn/10000],cnt;
int va1[maxn/10000],va2[maxn/10000],block;
bool in[maxn/10000];
int get(int x){return x<=block ? va1[x] : va2[n/x];}
void into(int x,int va){
    if(x<=block)va1[x]=va;
    else va2[n/x]=va;
}
void init(){
    for(int l=1,r;l<=n;l=r+1){
        r=n/(n/l);
        ++cnt;
        L[cnt]=l;
        R[cnt]=r;
    }
    DREP(i,cnt,1){
        mem(in);
        int b=n/L[i],sum=0;
        for(int l=1,r;l<=b;l=r+1){
            int c=b/l,tmp=get(L[i]*l);
            r=b/c;
            in[sum]=1;
            in[sum^tmp]=1;
            if((r-l+1)%2)sum^=tmp;
        }
        REP(j,0,maxn)if(!in[j]){
            into(L[i],j);
            break;
        }
    }
}
int main(){
    scanf("%d%d",&n,&q);
    block=sqrt(n);
    init();
    REP(i,1,q){
        int ans=0;
        scanf("%d",&m);
        REP(j,1,m){
            int u;
            scanf("%d",&u);
            ans^=get(u);
        }
        if(ans)puts("Yes");
        else puts("No");
    }
    return 0;
}

C++14(g++5.4) 解法, 执行用时: 889ms, 内存消耗: 984K, 提交时间: 2019-09-16 16:53:22

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#define re register
#define il inline
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define fp(i,a,b) for(re int i=a;i<=b;i++)
#define fq(i,a,b) for(re int i=a;i>=b;i--)
using namespace std;
const int mod=1e9+7,N=1e6+100;
int n,q,w,SG[2][N],ans,blk,b[N],id,vis[N];
il ll gi()
{
   re ll x=0,t=1;
   re char ch=getchar();
   while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
   if(ch=='-') t=-1,ch=getchar();
   while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
   return x*t;
}
il int getSG(re int x)
{
  x=n/(n/x);
  if(x<=blk) return SG[0][x];else return SG[1][n/x]; 
}
il void Pre()
{
    for(re int i=1;i<=n;i=n/(n/i)+1) b[++b[0]]=n/(n/i);
    fq(i,b[0],1)
    {
        re int x=b[i],now=0;++id;vis[0]=id;
        for(re int j=x+x;j<=n;)
        {
            re int t=(n/(n/j))/x*x,tmp=(t-j)/x+1;
            vis[now^getSG(j)]=id;
            if(tmp&1) now^=getSG(j);
            j=t+x;
        }
        re int tmp=0;while(vis[tmp]==id) ++tmp;
        if(x<=blk) SG[0][x]=tmp;else SG[1][n/x]=tmp;
    }
}
int main()
{
  n=gi();q=gi();blk=sqrt(n)+1;
  Pre();
  while(q--)
  {
      ans=0;w=gi();
      fp(i,1,w) ans^=getSG(gi());
      puts(ans?"Yes":"No");
    }
  return 0;
}

C++(clang++ 11.0.1) 解法, 执行用时: 552ms, 内存消耗: 700K, 提交时间: 2022-09-19 16:35:57

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
typedef long long ll;
int a[N];
int sg[N][2],mex[N];
int n,m;
int next(int x,int y)
{
    return x==y?x+1:y/(y/(x+1));
}
void init()
{
    for(int i=1;i<=n;i=next(i,n))
    {
        for(int k=2,tmp=0;k<=i;k=next(k,i))
        {
            int x=i/k;
            int t=(x>m)?sg[n/x][1]:sg[x][0];
            mex[tmp^t]=i;
            if((i/x-i/(x+1))&1) tmp^=t;
        }
        int tmp=1;
        while(mex[tmp]==i) tmp++;
        ((i>m)?sg[n/i][1]:sg[i][0])=tmp;
    }
}
int main()
{
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int t;
    cin>>n;
    m=floor(sqrt(n));
    init();
    cin>>t;
    while(t--)
    {
        int k;
        cin>>k;
        int ans=0;
        for(int i=1;i<=k;i++)
        {
            int x;
            cin>>x;
            ans^=(n/x>m?sg[n/(n/x)][1]:sg[n/x][0]);
        }
        if(ans) puts("Yes");
        else puts("No");
    }
}

上一题