• [HNOI2014]江南乐


    题目描述

    小A是一个名副其实的狂热的回合制游戏玩家。在获得了许多回合制游戏的世界级奖项之后,小A有一天突然想起了他小时候在江南玩过的一个回合制游戏。

    游戏的规则是这样的,首先给定一个数F,然后游戏系统会产生T组游戏。每一组游戏包含N堆石子,小A和他的对手轮流操作。每次操作时,操作者先选定一个不小于2的正整数M (M是操作者自行选定的,而且每次操作时可不一样),然后将任意一堆数量不小于F的石子分成M堆,并且满足这M堆石子中石子数最多的一堆至多比石子数最少的一堆多1(即分的尽量平均,事实上按照这样的分石子万法,选定M和一堆石子后,它分出来的状态是固定的)。当一个玩家不能操作的时候,也就是当每一堆石子的数量都严格小于F时,他就输掉。(补充:先手从N堆石子中选择一堆数量不小于F的石子分成M堆后,此时共有N+M-1)堆石子,接下来小A从这N+M-1堆石子中选择一堆数量不小于F的石子,依此类推。

    小A从小就是个有风度的男生,他邀请他的对手作为先手。小A现在想要知道,面对给定的一组游戏,而且他的对手也和他一样聪明绝顶的话,究竟谁能够获得胜利?

    输入输出格式

    输入格式:

    输入第一行包含两个正整数T和F,分别表示游戏组数与给定的数。 接下来T行,每行第一个数N表示该组游戏初始状态下有多少堆石子。之后N个正整数,表示这N堆石子分别有多少个。

    输出格式:

    输出一行,包含T个用空格隔开的0或1的数,其中0代表此时小A(后手)会胜利,而1代表小A的对手(先手)会胜利。

    输入输出样例

    输入样例#1:

    4 3
    1 1
    1 2
    1 3
    1 5

    输出样例#1:

    0 0 1 1

    说明

    对于100%的数据,T<100,N<100,F<100000,每堆石子数量<100000。

    以上所有数均为正整数。


    题解

    可以看出这是一个(Multi\_nim)游戏
    那么我们要求出大小为(x)的一堆石子的(SG(x))
    可以枚举(m),然后大小为(frac{x}{m}+1)的有(x\%m)
    ,大小为(frac{x}{m})的有(m-x\%m)
    由于是若干个相同的游戏异或
    所以只有游戏个数为奇数时才有贡献
    这样(SG(x)=mex(SG(frac{x}{m})[m-x\%m mod 2]oplus SG(frac{x}{m}+1))[x\%m mod 2])
    这样的复杂度是(O(n^2))
    那么我们考虑怎么来搞这个题
    可以发现要求一个函数的(SG)值需要的就是(SG(frac{x}{m}))(SG(frac{x}{m}+1))
    这类似于整除分块
    所以直接对(x)整除分块即可

    代码

    #include<vector>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    const int M = 100005 ;
    using namespace std ;
    inline int read() {
        char c = getchar() ; int x = 0 , w = 1 ;
        while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }
        while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
        return x*w ;
    }
    
    bool exist[M] ;
    int vis[M] ;
    int F , n , sg[M] ;
    
    int SG(int x) {
        if(x < F) return 0 ;
        if(exist[x]) return sg[x] ;
        for(int l = 2 , r ; l <= x ; l = r + 1) {
            r = x / (x / l) ;
            for(int m = l ; m <= min(l + 1 , x) ; m ++) {
                int tmp = 0 ;
                if((x % m) % 2) tmp ^= SG(x / m + 1) ;
                if((m - x % m) % 2) tmp ^= SG(x / m) ;
                vis[tmp] = x ;
            }
        }
        for(int i = 0 ; i <= x + 1 ; i ++)
            if(vis[i] != x) {
                sg[x] = i ;
                break ;
            }
        exist[x] = true ;
        return sg[x] ;
    }
    int main() {
        int Case = read() ; F = read() ;
        while(Case --) {
            n = read() ; int ans = 0 ;
            for(int i = 1 , x ; i <= n ; i ++) {
                x = read() ;
                ans ^= SG(x) ;
            }
            if(!ans) printf("0 ") ;
            else printf("1 ") ;
        }
        return 0 ;
    }
    
  • 相关阅读:
    ios webapp调试神器MIHTool
    20个正则表达式
    jQuery技巧
    浏览器判断和移动端的判断
    JavaScript 被忽视的细节
    移动端Web页面问题解决方案
    virtualenv创建虚拟环境
    init.d文件夹
    python連接mysql數據庫
    const和define的使用区别
  • 原文地址:https://www.cnblogs.com/beretty/p/10759313.html
Copyright © 2020-2023  润新知