题目链接: Deleting Divisors
大致题意
给定一个整数n. 操作: 把n减去一个因子, 这个因子不能是n和1.
现在Alice和Bob轮流对n进行操作, 谁不能操作谁就输了.
解题思路
考虑到最终的必败态: 这个数字为1 或者 这个数字是质数 则必败.
如果我们拿到的n是偶数(n != 2), 则我们一定可以进行操作. 我们可以把此时的n写作: n = 2k * odd1 * odd2 * … * oddq, 我们任意减去奇数因子, 对方一定拿到奇数. 一个奇数的因子一定是没有偶数的, 因此对方只能把n减去奇数因子, 相当于对方给我们了一个偶数. 如此反复, 我们可以必胜, 因为奇质数只会在对方的手中.
但这里有两个问题:
①我们只说了奇质数会在对方手中, 我们会不会拿到偶质数2呢?
②如果没有奇数因子呢? 相当于 n = 2k (k > 1)的形式. 或者随着游戏进行, n变成了2k的形式.
对于问题①, 我们拿不到2, 也拿不到2的整次幂(问题②), 因为没有一个奇数x的约数(不包括1和他自身), 与x差2的整次幂.
假设x为奇数, 不妨令 x = a * b. 此时如果a和b一奇一偶, 则a - b一定为奇数.
反之考虑a和b都是奇数的情况, 我们可以写成 x = a * (a + 2k) <==> x = (a * a) + (a * 2k), 此时 a * a一定为奇数, 而 a * 2k也是个奇数, 两个奇数相加, 结果一定是个偶数, 与x为奇数矛盾, 故不成立.
因此得证, 若n中有奇数因子, 先手确实必胜.
对于问题②, 相当于先手只能返还给对方一个偶数n’. 而此时, 如果n中含有奇数因子, 相当于交换了先后手, 此时先手必败. 因此我们一定返回给后手一个没有奇数因子的偶数, 因此我们只能给后手n' = n / 2
. 此时后手也是这样的想法, 他会给我们 n'' = n' / 2
.
如此反复, 我们发现, 如果n = 2k, k为奇数时, 先手必败, 反之必胜.
AC代码
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
typedef long long ll;
int main()
{
int t; cin >> t;
while (t--) {
int n; scanf("%d", &n);
if (n == 1 or n == 2) { puts("Bob"); continue; }
int k = log2(n);
if (n == (1 << k)) printf("%s\n", k & 1 ? "Bob" : "Alice");
else printf("%s\n", n & 1 ? "Bob" : "Alice");
}
return 0;
}
感觉分析细节是真的多QAQ, 当时比赛的时候也没想这么明白, 就猜了猜规律.