【SG函数】POJ - 3537 Crosses and Crosses

Step1 Problem:

在 1*n 的格子里面画 ×,谁画后有连续三个 × 的获胜。

Step2 Ideas:

SG函数学习博客
SG函数:状态 x,的函数值对应 sg[x], 状态 x 的下一个状态的函数值为 0 到 (sg[x]-1)。所以求 SG 函数值 = 不属于 下一个状态的函数值的集合 的非负的最小整数,例 mex{0, 1, 2, 4} = 3。
用到 SG 函数定理:把原游戏分解成多个独立的子游戏,则原游戏的SG函数值是它的所有子游戏的SG函数值的异或
即SG(G) = SG(G1) ^ SG(G2) ^ …. ^ SG(Gn)
简单证明下
例:SG(G) = 7 ^ 10 ^ 9。通过改变 7 变为 0~6,或者改变 10 变为 0~9,或者改变 9 变为 0~8 后异或的结果可以变为 0~(SG(G)-1),肯定变成不了 SG(G)
改变后使得异或的结果变为 0:观察 XOR 的二进制最高位 1,选取其中数的二进制表示对应位也为 1 的数。只要取走使得该位变为 0,且其余XOR中的 1 也反转的数量,XOR 就可以变成零,同理变成 1~(SG(G)-1)也一样
本题核心点:在第 i 个位置画后的状态变成两个子游戏,i-3 和 n-i-2.

Step3 Code:

#include<cstdio>
#include<cstring>
using namespace std;
const int N = 2e3+5;
int sg[N];
int dfs(int x)
{
    if(x <= 0) return 0;
    if(sg[x] != -1) return sg[x];
    int mex[N] = {0};// 等价于memset(mex, 0, sizeof(mex));
    for(int i = 1; i <= x; i++)
    {
        int t = dfs(i-3) ^ dfs(x-i-2);
        mex[t] = 1;
    }
    for(int i = 0; ;i++)
        if(!mex[i]) return sg[x] = i;
}
int main()
{
    memset(sg, -1, sizeof(sg));
    int n;
    while(~scanf("%d", &n))
    {
        if(dfs(n)) printf("1\n");
        else printf("2\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值