[BZOJ 1228] E&D

本文通过实例解析了如何运用Sprague-Grundy定理解决博弈论问题,并提出了一种高效求解SG函数的方法。文章详细介绍了SG函数的性质及求解步骤,通过观察规律简化计算过程。

Link:https://www.lydsy.com/JudgeOnline/problem.php?id=1228

 

Solution:

感觉自己对博弈论的理论一直了解得不够透彻

一篇讲原理的文章:Sprague-Grundy定理是怎么想出来的

现在发现其实可以将SG函数的合成看作为Nim游戏,也顺便能证明其异或运算的正确性了

 

对于此题,发现每两堆之间明显是独立的,于是只要求出每组的SG值再异或即可

但直接求解SG复杂度过高,于是采取打表找规律的方式

 

0出现条件: i,j均%2=1
 
  
1出现条件: i,j均%4=1或2
 
  
2出现条件: i,j均%8=1或2或3或4
 

得到sg(i,j)=k的必要条件:

(i-1)%2^(k+1) < 2^k && (j-1)%2^(k+1) < 2^k

 

这样便能在O(logS)时间内求出SG函数

 

Code:

 

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
int t,n,x,y;

int SG()
{
    ll pro=2;
    for(int i=0;;++i,pro<<=1)
        if(((x-1)&(pro-1))<(pro>>1) && ((y-1)&(pro-1))<(pro>>1)) return i;
}

int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);int res=0;
        for(int i=1;i<=n/2;i++)
            scanf("%d%d",&x,&y),res^=SG();
        puts(res?"YES":"NO");
    }
}

 

Review:

1、求解A%2^k的技巧:

      直接求解 A&(2^k - 1) 即可,大大优化常数

 

2、求解SG函数的一般步骤:

(1) 使用 数组f 将 可改变当前状态的方式 记录下来。(一般SG函数成规律性变化)

(2) 然后我们使用 另一个数组 将当前状态x 的后继状态标记。

(3) 最后模拟mex运算,也就是我们在标记值中 搜索 未被标记值 的最小值,将其赋值给SG(x)。

 

3、如果求解SG函数复杂度过高,考虑打表找规律的方式

转载于:https://www.cnblogs.com/newera/p/9095559.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值