AcWing
  • 首页
  • 课程
  • 题库
  • 更多
    • 竞赛
    • 题解
    • 分享
    • 问答
    • 应用
    • 校园
  • 关闭
    历史记录
    清除记录
    猜你想搜
    AcWing热点
  • App
  • 登录/注册

AcWing 3079. 取石子游戏 : 集合 Nim    原题链接    困难

作者: 作者的头像   CYMario ,  2024-08-04 20:55:45 ,  所有人可见 ,  阅读 25


1


就是 AcWing 893.集合-Nim游戏 加一个先手必胜时的具体解。

我们知道当所有子游戏 sg 函数的异或和非 0 时为先手必胜,是 0 则先手必败。那么只要先手取完之后让 sg 值变成 0 即可。所以我们暴力枚举就好了。注意一下异或符号和判等符号的优先级,打一下括号就行。

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <unordered_set>
const int N = 110, M = 11010;
int m, n;
int s[N], sg[M], a[N];
int get_sg(int x)
{
    if (sg[x] >= 0)
        return sg[x];
    std::unordered_set<int> S;
    for (int i = 1; i <= m; ++i)
        if (x >= s[i])
            S.insert(get_sg(x - s[i]));
    for (int i = 0; i <= S.size(); ++i)
        if (!S.count(i))
            return sg[x] = i;
    return sg[x] = -1;
}
int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i)
        scanf("%d", &a[i]);
    scanf("%d", &m);
    for (int i = 1; i <= m; ++i)
        scanf("%d", &s[i]);
    int ans = 0;
    memset(sg, -1, sizeof(sg));
    for (int i = 1; i <= n; ++i)
        ans ^= get_sg(a[i]);
    puts(ans ? "YES" : "NO");
    if (ans)
    {
        bool fin = 0;
        for (int i = 1; i <= n && !fin; ++i)
            for (int j = 1; j <= m && s[j] <= a[i] && !fin; ++j)
                if ((ans ^ get_sg(a[i]) ^ get_sg(a[i] - s[j])) == 0)
                    fin = 1, printf("%d %d\n", i, s[j]);
    }
}

0 评论

App 内打开
你确定删除吗?
1024
x

© 2018-2025 AcWing 版权所有  |  京ICP备2021015969号-2
用户协议  |  隐私政策  |  常见问题  |  联系我们
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标 qq图标
请输入绑定的邮箱地址
请输入注册信息