acwing894. 拆分-Nim游戏

acwing894. 拆分-Nim游戏

原题链接:https://www.acwing.com/problem/content/896/

思路

关于SG函数,mex操作,SG定理的一些知识

取走一堆放入两堆,好像总的堆数一直在增加,但是每次放入的两堆各堆的数量一定小于取走的那一堆的数量,可能到最后每次放入的两堆的数量都是0,所以是有终点的。

此题将每一堆石子看成独立的局面

将每堆石子看做独立的局面,即a1a2a3...an个有向图游戏。

然后求每个局面的SG函数SG(a1)SG(a2)SG(a3)...SG(an),求其异或和

SG(a1)SG(a2)SG(a3)...SG(an)0则先手必胜
SG(a1)SG(a2)SG(a3)...SG(an)=0则先手必败

对于每一个有向图a1a2a3...an都存在如下情况:拿走ak,增加了b1b2两堆石子,根据SG定理SG(ak)=SG(b1)SG(b2)

代码
#include<iostream>
#include<cstring>
#include<unordered_set>

using namespace std;

const int N = 110;

int f[N],a[N];
int n;

int SG(int x)
{
    // 如果已经计算过SG函数值的直接返回
    if(f[x] != -1) return f[x];
    
    unordered_set<int> S; // 记录这个图x中的所有SG函数值
    
    // 遍历所有可能
    for(int i = 0; i < x; i ++)
        for(int j = 0; j <= i; j ++) // 这里可以取等,遍历到i就行,因为会有重复
            S.insert(SG(i)^SG(j));
    
    // mex
    for(int i = 0;; i ++)
    {
        if(!S.count(i)) return f[x] = i;
    }
}

int main()
{
    cin >> n;
    for(int i = 0; i < n; i ++) cin >> a[i];
    
    memset(f,-1,sizeof f);
    
    int res = 0;
    for(int i = 0; i < n; i ++)
        res ^= SG(a[i]);
        
    if(res) puts("Yes");
    else puts("No");
    
    return 0;
}
posted @   r涤生  阅读(46)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示