题目链接

小红和小紫的取素因子游戏

题目描述

小红和小紫有一个正整数 ,她们轮流进行操作。每位玩家可以选择 的一个素因子 ,然后将 替换为 。小红先手。当轮到某位玩家时,如果当前的数 ,则她无法操作,判为失败。假设两人都采取最优策略,请判断谁会获胜。

解题思路

这是一个公平组合游戏(Impartial Game),因为对于任何一个游戏状态(当前的数字 ),可行的操作集合只取决于状态本身,而与轮到哪位玩家无关。

游戏的核心操作是将 替换为 。如果我们考虑 的质因数分解形式 ,那么每次操作实际上就是将某个质因子 的指数 减一。

游戏结束的条件是 ,此时所有的质因子的指数都变为了 0。这意味着,从任意一个初始的 开始,游戏能够进行的总步数是固定的,它等于 的所有质因子(计入重复)的总个数,即

例如,如果 ,那么总的质因子个数是 。无论玩家如何选择(先除以2,还是先除以3),游戏都将精确地进行 3 步。

既然总步数是固定的,那么我们就可以根据总步数的奇偶性来判断胜负:

  • 如果总步数是奇数,那么先手(小红)将进行第 1, 3, 5, ..., 最后一(奇数)步。小红走完最后一步后,数字变为 1,轮到小紫时无法操作,所以小红获胜。
  • 如果总步数是偶数(或0),那么后手(小紫)将进行第 2, 4, 6, ..., 最后一(偶数)步。小紫走完最后一步后,数字变为 1,轮到小红时无法操作,所以小紫获胜。

因此,问题就转化为了:计算给定整数 的总质因子数量,并判断其奇偶性。我们可以使用试除法来统计总质因子数。

代码

#include <iostream>

using namespace std;

void solve() {
    long long x;
    cin >> x;
    int total_moves = 0;
    
    // 试除法统计质因子总数
    for (long long i = 2; i * i <= x; ++i) {
        while (x % i == 0) {
            total_moves++;
            x /= i;
        }
    }
    // 如果 x 最后还剩下大于 1 的数,它本身也是一个质因子
    if (x > 1) {
        total_moves++;
    }
    
    // 根据总步数奇偶性判断胜负
    if (total_moves % 2 != 0) {
        cout << "kou\n";
    } else {
        cout << "yukari\n";
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int t = sc.nextInt();
        while (t-- > 0) {
            long x = sc.nextLong();
            int total_moves = 0;
            
            // 试除法统计质因子总数
            for (long i = 2; i * i <= x; ++i) {
                while (x % i == 0) {
                    total_moves++;
                    x /= i;
                }
            }
            // 如果 x 最后还剩下大于 1 的数,它本身也是一个质因子
            if (x > 1) {
                total_moves++;
            }
            
            // 根据总步数奇偶性判断胜负
            if (total_moves % 2 != 0) {
                System.out.println("kou");
            } else {
                System.out.println("yukari");
            }
        }
    }
}
t = int(input())
for _ in range(t):
    x = int(input())
    total_moves = 0
    
    # 试除法统计质因子总数
    i = 2
    while i * i <= x:
        while x % i == 0:
            total_moves += 1
            x //= i
        i += 1
        
    # 如果最后 x 还大于 1,说明剩下的 x 也是一个质因数
    if x > 1:
        total_moves += 1
    
    # 根据总步数奇偶性判断胜负
    if total_moves % 2 != 0:
        print("kou")
    else:
        print("yukari")

算法及复杂度

  • 算法:博弈论 + 试除法
  • 时间复杂度:对于每组测试数据,时间复杂度为 。总时间复杂度为 ,其中 是游戏局数, 是给定的整数。
  • 空间复杂度:,只需要常数空间。