SG函数/Nim

P2197 【模板】Nim 游戏 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

思路:最模板的SG函数.

因为可以取1到x个石子,那么x的后继状态为[0,x-1],那么sg(x)=x.
int n;
P2197 【模板】Nim 游戏
https://www.luogu.com.cn/problem/P2197
void solve(){
    cin>>n;
    int ans=0;
    for(int i=1;i<=n;i++){    因为可以取1到x个石子,那么x的后继状态为[0,x-1],那么sg(x)=x.
        int x; cin>>x;
        ans^=x;
    }
    if(ans!=0) cout<<"Yes"<<endl;
    else cout<<"No"<<endl;
}

C-小w和大W的决斗。_河南萌新联赛2024第(二)场:南阳理工学院 (nowcoder.com)

思路:

枚举x的后继状态和枚举x的后继三种子游戏状态。暴力求SG值。
int n;
int sg[105];  石头堆大小为i的sg值为sg[i].
int getSG(int x){
    if(sg[x]!=-1) return sg[x];
    vector<int> vis(105,0);
    for(int i=0;i<x;i++){  枚举x的后继状态
        vis[getSG(i)]=1;
    }
    for(int i=1;i<x;i++){   枚举x的后继三种子游戏状态
        for(int j=1;j+i<x;j++){
            int k=x-i-j;
            vis[getSG(i)^getSG(j)^getSG(k)]=1;
        }
    }
    int mex=0;
    while(vis[mex]) mex++;
    return sg[x]=mex;
}
问题:sg怎么处理分成三堆的操作? 枚举x的后继三种子游戏状态
小w和大W的决斗。  题目没说清楚..i+j+k=x,是分成3个"非空"的堆
https://ac.nowcoder.com/acm/contest/87255/C
void solve(){           模板题
    for(int i=0;i<=100;i++) sg[i]=-1;  init;
    sg[0]=0;
    getSG(100);
    cin>>n;
    int ans=0;
    for(int i=1;i<=n;i++){
        int x; cin>>x;
        ans^=sg[x];
    }
    if(ans!=0) cout<<"w win"<<endl;
    else cout<<"W win"<<endl;
}

[ABC297G] Constrained Nim 2 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

思路:

这题有2e5堆石子,每堆石子有1e9个石头,每次可以取[l,r]个,并且l,r取值最大也是1e9。数据范围这么大怎么求sg?
不能暴力求了,得推导公式(not easy)..或者暴力求sg打表找规律(更可能实现)
通过打表找规律发现,不同的l,r,计算sg(x)的公式为sg(x)=(x%(l+r))/l;
规律..不好发现..但是也不是说完全不能发现...循环的部分x%(l+r)是好发现的.但是除以l就没发觉了..
int n,l,r;
int sg[55];
int getSG(int x){
    if(sg[x]!=-1) return sg[x];
    vector<int> vis(55,0);
    for(int i=max(x-r,0ll);i<=x-l;i++) vis[getSG(i)]=1;
    int mex=0;
    while(vis[mex]) mex++;
    return sg[x]=mex;
}
这题有2e5堆石子,每堆石子有1e9个石头,每次可以取[l,r]个,并且l,r取值最大也是1e9。数据范围这么大怎么求sg?
不能暴力求了,得推导公式(not easy)..或者暴力求sg打表找规律(更可能实现)
通过打表找规律发现,不同的l,r,计算sg(x)的公式为sg(x)=(x%(l+r))/l;
规律..不好发现..但是也不是说完全不能发现...循环的部分x%(l+r)是好发现的.但是除以l就没发觉了..
[ABC297G] Constrained Nim 2
https://www.luogu.com.cn/problem/AT_abc297_g
void solve(){          nim
//    cin>>l>>r;
//    for(int i=0;i<=50;i++) sg[i]=-1;  init
//    sg[0]=0;
//    for(int i=1;i<=50;i++) getSG(i);
//    for(int i=0;i<=50;i++) cout<<sg[i]<<" ";
    cin>>n>>l>>r;
    int ans=0;
    for(int i=1;i<=n;i++){
        int x; cin>>x;
        ans^=( (x%(l+r))/l );
    }
    if(ans!=0) cout<<"First";
    else cout<<"Second";
}

P2252 [SHOI2002] 取石子游戏|【模板】威佐夫博弈 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

思路:这个不是SG函数,记结论吧。

奇异局势:小堆的个数等于两堆的差值*(sqrtl(5.0)+1.0)/2.0--注意开long double
P2252 [SHOI2002] 取石子游戏|【模板】威佐夫博弈--奇异局势:A=(B-A)*(sqrt(5)+1)/2    A是小堆石头个数,B为大堆
奇异局势:小堆的个数等于两堆的差值*(sqrtl(5.0)+1.0)/2.0
https://www.luogu.com.cn/problem/P2252
void solve(){
    int A,B; cin>>A>>B;
    if(A>B) swap(A,B);
    int Z=B-A;
    long double wyf=(sqrtl(5.0)+1.0)/2.0;   开long double,并且用sqrtl求根号!
    if(A==(int)(wyf*(double)Z)) cout<<"0";
    else cout<<"1";
}

 

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值