题目
Game
分解质因数,博弈
思路
博弈论一般是两极分化的,要么有思路,相当简单;要么没思路,死活想不出来。
所以一般先找规律,然后大胆猜想,最后提交验证
这道题有什么规律呢?
可以得出以下表格:
给定数 | 先手赢 |
---|---|
1 | ✘ |
2 | ✘ |
3 | ✘ |
4 | ✔ |
5 | ✘ |
6 | ✔ |
7 | ✘ |
8 | ✘ |
9 | ✔ |
10 | ✔ |
由以上表格,和再深入一点点的猜想,可以得出:
当给定数是 1 1 1 或者是素数时( 1 1 1 不是素数),先手输,因为素数的因子只有 1 1 1 和它本身,所以不可能分出非 1 1 1 的两个因子
那么对于合数呢?
既然上面牵扯到了素数(这是一个启发点),那么我们对合数的质因子进行研究,可以得出:
给定数 | 先手赢 |
---|---|
4 = 2 × 2 4=2\times 2 4=2×2 | ✔ |
6 = 2 × 3 6=2\times 3 6=2×3 | ✔ |
8 = 2 × 2 × 2 8=2\times 2\times 2 8=2×2×2 | ✘ |
9 = 3 × 3 9=3\times 3 9=3×3 | ✔ |
10 = 2 × 5 10=2\times 5 10=2×5 | ✔ |
可以很明显地看出,当给定的数是质因子个数为 3 3 3 的 8 8 8 时,先手才输,其余情况的质因子个数都是 2 2 2,那么可否得出下面这个大胆的猜想呢?
当质因子个数为奇数时,先手输,否则,先手赢
这个猜想也能包含给定数是素数的情况(素数的质因子个数为 1 1 1)。但是不包含给定数是 1 1 1 的情况,所以 1 1 1 需要特判。
经过验证,这个猜想是正确的,但这里不给出证明
注意
题目求的是无法进行操作的人的名字
代码
#include <stdio.h>/*** @brief 获取给定正整数的质因数个数** @param n 一个给定的正整数* @return int 给定数的质因数个数*/
int get_prime_fac_num(int n) {int res = 0, d = 2;for (int i = 2; i * i <= n; i++) {if (n % i == 0) {while (n % i == 0) {n /= i;res++;}}}if (n > 1) res++;return res;
}/*** @brief 判断先手是否赢** @param n 给定的数* @return int 0 表示输*/
int check(int n) {// 如果给定数为 1 或者质因数个数为奇数,则先手输,否则先手赢return (n ^ 1) && !(get_prime_fac_num(n) & 1);
}int main(void) {int n = 0;scanf("%d", &n);printf("%s\n", check(n) ? "Johnson" : "Nancy");return 0;
}