P4018 Roy&October之取石子

题目背景

Roy和October两人在玩一个取石子的游戏。

题目描述

游戏规则是这样的:共有n个石子,两人每次都只能取p^kp
k
个(p为质数,k为自然数,且p^kp
k
小于等于当前剩余石子数),谁取走最后一个石子,谁就赢了。

现在October先取,问她有没有必胜策略。

若她有必胜策略,输出一行"October wins!";否则输出一行"Roy wins!"。

输入输出格式

输入格式:
第一行一个正整数T,表示测试点组数。

第2行~第(T+1)行,一行一个正整数n,表示石子个数。

输出格式:
T行,每行分别为"October wins!"或"Roy wins!"。

输入输出样例

输入样例#1: 复制
3
4
9
14
输出样例#1: 复制
October wins!
October wins!
October wins!
说明

对于30%的数据,1<=n<=30;

对于60%的数据,1<=n<=1,000,000;

对于100%的数据,1<=n<=50,000,000,1<=T<=100,000。

(改编题)

看似这个题很复杂的样子,每一次可以在数里取走(为整数且p^k(k为整数,且ge 0))

那这一看就是博弈论吧。于是考虑所有的必胜态。

显然,当前这个数为(为质数p(p为质数))的次幂都可以必胜。

那根据博弈观点,所有的通过一次到达上面状态的都是必败态。

于是有下面的办法

pri[maxn]//全为质数
//cnt为选出的质数个数
dp[1]=1;
for(int k=2;k<=max;k++)
for(int i=1;i<cnt;i++)
	for(int j=1;j;j*=cnt[i])
		if(!dp[k-j])dp[k]=1;

这样就可以找出所有的数了。

太慢了有木有。。。

于是打表发现所有的必败态都是6的倍数

于是

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read(){
    int an=0;
    char ch=getchar();
    while(ch<'0'||ch>'9'){ch=getchar();}
    while('0'<=ch&&ch<='9'){an=an*10+(ch^48);ch=getchar();}
    return an;
}
int n;
int main(){
    ios::sync_with_stdio(0);
    n=read();
    for(;n;n--){
        int x=read();
        if(x%6)cout<<"October wins!
";
        else cout<<"Roy wins!
";
    }
    return 0;
}

原文地址:https://www.cnblogs.com/ck666/p/8097329.html