Number Game

传送门
以前博弈论都是靠找规律,这个题给我了新的思路,就是如果说博弈论里面的操作是对数字操作,那么可以采用递推的形式
先初始化(sqrt(n))的数据,然后有种杜教筛的思想,对于(n > N)时,才回去继续查找,而在求dp[n / j]时,继续查看,n / j 是否 < N

设dp[i], 如果dp[i] = 1,表示i这个数字是先手必胜,2则为后手必胜
本题就是如果说n是一个除了1外的奇数,直接除以本身即可,那么就是先手胜利,否则,对于偶数来说
(sqrt(n))找自己的所有因子,如果说除以因子后的dp是2,表示我操作后的值是后手必胜,那么我可以赢。最后默认为2。

#include <iostream>
#include <cstdio>
using namespace std;
const int N = 1e5 + 5;
int dp[N];
void init(int n){//初始化
    dp[1] = 2; dp[2] = dp[3] = 1; dp[4] = 2; dp[5] = 1; dp[6] = 2;
    for(int i = 7; i <= n; i++){
        if(dp[i - 1] == 2 || i % 2 == 1) {//我减去1后为后手必胜,或者为奇数,则我先手必胜
            dp[i] = 1;
            continue;
        }
        for(int j = 2; j * j <= i; j++){//偶数进行查找
            if(i % j == 0){
                if(dp[i / j] == 2 && j & 1) {
                    dp[i] = 1;
                    break;
                }
                if(j * j != i && (i / j) & 1 && dp[j] == 2){
                    dp[i] = 1;
                    break;
                } 
            }
        }
        if(!dp[i]) dp[i] = 2;//默认值
    }
}
int cal(int n){//杜教筛思想的搜索
    if(n < N - 2) return dp[n];
    if(n & 1) return 1;
    for(int i = 2; i * i <= n; i++){
        if(n % i == 0){
            if(cal(n / i) == 2 && i & 1)
                return 1;
            if(i * i != n && (n / i) & 1 && cal(i) == 2) 
                return 1;
        }
    }
    return 2;
}
int main(){
    init(N - 2);
    int t;
    cin >> t;
    while(t--){
        int n;
        cin >> n;
        if(cal(n) == 1) printf("Ashishgup
");
        else printf("FastestFinger
");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Emcikem/p/13218005.html