fibgame 解题报告
1.fibgame 解题报告
题外话
赛时蒟蒻 SG 函数推导 2h 未果,看来我博弈论还得练。
题目描述
定义
- 若
,则 为空树; - 若
,则 为单独一个节点; - 若
,则 是一个根节点连接两个子树,分别为 和 。
小 Z 和小 W 在树上玩游戏,小 Z 先手。每次玩家可以选择一个节点 ,然后将以 为根的子树全删去。规定取到根节点的人输。
下面给出了 ∼ 的图例,其中红点表示小 Z 第一步的必胜点。
现在小 Z 想让你帮他数一数:
对于
解题思路
显然这道题类似「公平组合游戏」。因此根据套路先考虑求 SG 函数。
策略分析
「公平组合游戏」的定义如下:
- 游戏有两个人参与,二者轮流做出决策,双方均知道游戏的完整信息;
- 任意一个游戏者在某一确定状态可以作出的决策集合只与当前的状态有关,而与游戏者无关;
- 游戏中的同一个状态不可能多次抵达,游戏以玩家无法行动为结束,且游戏一定会在有限步后以非平局结束。
在这道题中,「玩家无法行动」指的是「整棵树只剩下了根节点」。
SG 函数
定义
考虑定义
- 全部删除子树
- 删除
的子树
因为
因此,设节点
点数计算
胜利点的数量计算有多种方式。这里采用 std 的实现。
设
因为
综上所述,
打表发现
代码实现
#include <bits/stdc++.h> using namespace std; const int mod = 998244353; int n, sg[10010], dp[10010][10010]; bitset<10010> vis[10010]; int pd(int i, int j) { if (vis[i][j]) return dp[i][j]; if (i < 2) return 0; if (i == 2 && j != 0) return 0; vis[i][j] = 1; return dp[i][j] = (((j == sg[i - 2] + 1) ? 1 : pd(i - 1, (j ^ (sg[i - 2] + 1)) - 1)) + ((j == sg[i - 1] + 1) ? 1 : pd(i - 2, (j ^ (sg[i - 1] + 1)) - 1))) % mod; } int main() { #ifndef CWKAPN freopen("fibgame.in", "r", stdin); freopen("fibgame.out", "w", stdout); #endif scanf("%d", &n); if (n == 1) { printf("0\n"); return 0; } if (n == 2) { printf("1\n"); return 0; } sg[1] = 0, sg[2] = 1; for (int i = 3; i <= n; i++) sg[i] = (sg[i - 1] + 1) ^ (sg[i - 2] + 1); vis[2][0] = 1; dp[2][0] = 1; printf("%d\n", pd(n, 0)); return 0; }
本文来自博客园,作者:cwkapn,转载请注明原文链接:https://www.cnblogs.com/chenaknoip/p/18721915
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)