题目描述
https://www.luogu.com.cn/problem/P1290
Solution
我们不妨令当前局面为 ,其中
注意到问题可以转换为有 堆按照顺序排好的石子,每个人只能操作第一堆石子,每次可以拿任意个
注意到如果当前第一堆石子的数量大于 ,那么先手必胜,因为无论将第一堆石子去掉之后的局面是必胜还是必败,先手总能获胜(如果必胜,那么将第一堆拿到剩 个,如果必败,直接将第一堆拿完
所以我们递归判断即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| #include <iostream> #include <cstdio> using namespace std;
int n, m;
bool dfs(int a, int b, int p) { if (a % b == 0) return p; if (a / b >= 2) return p; return dfs(b, a - b, p ^ 1); }
void work() { cin >> n >> m; if (n < m) swap(n, m); cout << (dfs(n, m, 1) ? "Stan wins" : "Ollie wins") << "\n"; }
int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
int T; cin >> T; while (T--) work(); return 0; }
|
现在唯一的问题就是假设我们有多个欧几里得游戏,那么我们就需要计算一个游戏的 值
我们不妨设有 堆石子,每堆石子的数量为
那么游戏的 值应该为
1 2 3
| int sg = a[n]; for (int i = n - 1; i; --i) sg = a[i] - (sg >= a[i]);
|
至于原因,我大概写一下(因为我也是猜的
首先对于第一堆之后的石子,我们不妨设其 值为 ,那么我们就能把后面一大堆石子替换成一堆有 个石子,不妨设第一堆石子有 个(正确性存疑
我们考虑暴力计算 的 值,我们有
注意到如果 ,那么如果 ,那么容易得到
如果 ,那么 ,那么 值的计算就如上式,我们倒着合并即可
正确性仍然存疑