• 【AT3939】[ARC091D] Strange Nim(博弈论)


    点此看题面

    • (n)堆石子,每堆石子初始有(a_i)个,且附带一个参数(k_i)
    • 每次可以从一堆石子(假设是第(i)堆,当前剩(x_i)个石子)中取出(1simlfloorfrac{x_i}{k_i} floor)个石子,判断谁必胜。
    • (nle200,a_i,k_ile10^9)

    (SG)函数

    根据(Nim)游戏的基本知识我们知道可以分别求出每堆石子的(SG)函数,然后异或在一起就是全局的(SG)函数了。

    一个显然的转移式:

    [SG(x)= exttt{mex}_{i=1}^{lfloorfrac xk floor}SG(x-i) ]

    看起来很诡异,但我们仔细想想便会找到一个性质,就是(x)的前(lfloorfrac xk floor+1)位应该是一个(0sim lfloorfrac xk floor)的排列!

    但如果(x)(k)的倍数时会存在例外,此时它的前(lfloorfrac xk floor)位是一个(0sim lfloorfrac xk floor-1)的排列,因此(SG(x)=lfloorfrac xk floor)

    证明只需归纳即可,应该还是比较容易的。

    那么我们可以列出一个简单的递推式:

    [SG(x)=egin{cases}0&x<k,\lfloorfrac xk floor&k|x,\SG(x-lfloorfrac xk floor-1)&x>k&&k ot|xend{cases} ]

    主要是考虑第三种转移,直接搞复杂度是(O(k))的,如果(k)很大可能会挂。

    但我们发现对于(lfloorfrac xk floor)相等的连续一段其实可以放一起转移,那么就只会转移(O(lfloorfrac ak floor))次。

    二者一结合,复杂度就是(O(sqrt a))的,正确了。

    代码:(O(nsqrt a))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    using namespace std;
    int n;I int SG(CI x,CI k)//求SG函数
    {
    	if(x<k) return 0;if(!(x%k)) return x/k;//x<k和x是k倍数的两种情况
    	RI y=x/k*k,d=x/k+1,t=(x-y)/d;return SG(x-max(t,1)*d,k);//x/k相同的一段一起转移
    }
    int main()
    {
    	RI i,x,k,t=0;for(scanf("%d",&n),i=1;i<=n;++i) scanf("%d%d",&x,&k),t^=SG(x,k);//把每堆石子的SG函数异或起来
    	return puts(t?"Takahashi":"Aoki"),0;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    使用RedisDesktopManager工具,解决连接失败问题
    安装redis,搭建环境
    CentOS 7下GitLab搭建及配置
    Metasploit之Hash攻击(Hashdump、Quarks PwDump、Windows Credentials Editor、Mimikatz)
    Metasploit之令牌窃取
    Metasploit之漏洞利用( Metasploitable2)
    Metasploit之主机扫描
    Metasploit模块简介
    WAF的那些事
    XXE漏洞介绍 & XXE漏洞攻击 & 修复建议
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/AT3939.html
Copyright © 2020-2023  润新知