码迷,mamicode.com
首页 > 编程语言 > 详细

[HAOI2015] 数组游戏 - 博弈论,SG函数

时间:2020-03-03 11:07:50      阅读:66      评论:0      收藏:0      [点我收藏+]

标签:一段   syn   pos   const   std   函数   行操作   for   int   

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

Solution

用暴力 SG 打个表,发现一段一段的 SG 值都是相同的,所以套个整除分块即可

#include <bits/stdc++.h>
using namespace std;

const int N = 400005;
int n,q,lim,sg[2][N],pos[N],u[N];

int SG(int x) {
    x=n/(n/x);
    if(x>lim) return sg[1][n/x];
    else return sg[0][x];
}

void presolve() {
    int cnt=0;
    for(int i=1,j;i<=n;i=j+1) {
        j=n/(n/i);
        pos[++cnt]=j;
    }
    while(cnt) {
        int x=pos[cnt], now=0, mex=1;
        u[now]=cnt;
        for(int i=x+x,j;i<=n;i=j+x) {
            j=n/(n/i)/x*x;
            u[now^SG(j)]=cnt;
            if((j-i)/x&1^1) now^=SG(j);
        }
        while(u[mex]==cnt) ++mex;
        if(x>lim) sg[1][n/x]=mex;
        else sg[0][x]=mex;
        --cnt;
    }
}

signed main() {
    ios::sync_with_stdio(false);
    cin>>n>>q;
    lim=sqrt(n);
    presolve();
    while(q--) {
        int m,x,ans=0;
        cin>>m;
        while(m--) {
            cin>>x;
            ans^=SG(x);
        }
        if(ans) cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }
}

[HAOI2015] 数组游戏 - 博弈论,SG函数

标签:一段   syn   pos   const   std   函数   行操作   for   int   

原文地址:https://www.cnblogs.com/mollnn/p/12400733.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!