SG函数模板题总结

这篇博客总结了三道与SG函数相关的博弈题目,包括S-Nim、A New Tetris Game(2)和Nim游戏。S-Nim通过记忆化搜索求解SG函数值;A New Tetris Game(2)中,将游戏状态转换为字符串并使用SG函数;Nim游戏中,探讨了如何用SG函数进行状态转移和规律发现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

S-Nim

HDU 1536

应该是最板的一道题了 q w q qwq qwq

k k k堆石子的博弈分解成 k k k个子问题再把它们的 SG \text{SG} SG 函数值异或起来, s g [ i ] sg[i] sg[i]表示 i i i个石子的 SG \text{SG} SG 函数值,记忆化搜索即可,注意:搜索过程中算 m e x mex mex v i s vis vis的大小就是操作集合的大小。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int M = 10005;
int read()
{
    int x=0,flag=1;char c;
    while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
    while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*flag;
}
int n,m,k,f[105],sg[M];
int get(int x)
{
    if(x==0) return 0;
    if(sg[x]!=-1) return sg[x];
    bool vis[105]={};
    for(int i=1;i<=n && f[i]<=x;i++)
        vis[get(x-f[i])]=1;
    for(int i=0;;i++)
        if(!vis[i])
            return sg[x]=i;
}
int main()
{
    while(~scanf("%d",&n) && n)
    {
        memset(sg,-1,sizeof sg);
        for(int i=1;i<=n;i++)
            f[i]=read();
        sort(f+1,f+1+n);
        m=read();
        while(m--)
        {
            k=read();
            int flag=0;
            for(int i=1;i<=k;i++)
                flag^=get(read());
            if(flag) putchar('W');
            else putchar('L');
        }
        puts("");
    }
}

A New Tetris Game(2)

点此看题

很暴力的一道题了,我们直接把图搞成字符串然后拿去跑 SG \text{SG} SG函数。

注意每一行后面要插入一个特殊字符,复杂度就别问我了(你觉得我算的出来吗? ),感性理解,状态数不会很多 ,然后就贴一个我的代码。

#include <cstdio>
#include <iostream>
#include <map>
using namespace std;
int read()
{
    int x=0,flag=1;char c;
    while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
    while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*flag;
}
int n,r,c;char g[55][55];
map<string,int> sg;
string _str()
{
    string s;
    for(int i=0;i<r;i++)
    {
        s+=g[i];
        s+='*';
    }
    return s;
}
int get()
{
    string x=_str();
    if(sg.count(x)) return sg[x];
    int vis[55]={};
    for(int i=1;i<r;i++)
        for(int j=1;j<c;j++)
            if(g[i][j]=='0' && g[i-1][j]=='0' && g[i][j-1]=='0' && g[i-1][j-1]=='0')
            {
                g[i][j]=g[i-1][j]=g[i][j-1]=g[i-1][j-1]='1';
                vis[get()]=1;
                g[i][j]=g[i-1][j]=g[i][j-1]=g[i-1][j-1]='0';
            }
    for(int i=0;;i++)
        if(!vis[i])
            return sg[x]=i;
}
int main()
{
    while(~scanf("%d",&n))
    {
        int flag=0;
        while(n--)
        {
            r=read();c=read();
            for(int i=0;i<r;i++) scanf("%s",g[i]);
            flag^=get();
        }
        if(flag) puts("Yes");
        else puts("No");
    }
}

Nim游戏(hihocoder)

点此看题

还是把原问题 n n n个子问题,考虑 SG \text{SG} SG函数,设 s g [ i ] sg[i] sg[i] i i i堆石子的 SG \text{SG} SG函数值,转移如下:
s g [ i ] = m e x { s g [ j ] , s g [ j ] ⊕ s g [ j − i ] } sg[i]=mex\{sg[j],sg[j]\oplus sg[j-i]\} sg[i]=mex{sg[j],sg[j]sg[ji]}然后就是打表找规律下面给出我打的表:

k     0 1 2 3 4 5 6 7 8 9 10 11 12sg(k) 0 1 2 4 3 5 6 8 7 9 10 12 11

规律很容易看出来,贴个代码 q w q qwq qwq

#include <cstdio>
int read()
{
    int x=0,flag=1;
    char c;
    while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
    while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*flag;
}
int n,ans;
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
    {
        int x=read();
        if(x%4==3) x++;
        else if(x%4==0) x--;
        ans^=x;
    }
    if(ans) puts("Alice");
    else puts("Bob");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值