51Nod1831 小C的游戏
Problem
小C和小L是好朋友,她们在玩一个游戏。
一开始有一个大小为n的石子堆,小C先手。
每次可以对这个石子堆拿走一个或者把这个石子堆分成等量的几份并只取其中一份(不能不变或只剩下一个)。
如果取走最后一个人的算败,请问这个游戏小C是否能胜。
Solution
SG打表,总体上是质数败,但有几个不一样的。
注意sg[1]=0,从sg[2]开始计算。
不需要算奇偶个异或,题目的意思是取出一份来,用这一份继续游戏。
最简单的做法就是找规律了,直接搜一下就能获得所有的胜负态。
仔细观察可以发现质数除了2和17就是败的,合数除了16,34和289都是赢的。
感觉这样是不太科学的,那就来讲讲道理。
我们发现2,4,8都是赢的,而16的后继状态都是赢的,所以它是败的,而2^n(n>4)都能转化到16。
同样的我们能说明17和2n17m。
我们考虑一个合数,它的因数肯定有个败态的,它就必胜了。
这样也就说明了质数是必败了。
Code
#include<stdio.h>
#include<set>
#include<iostream>
#include<stack>
#include<cstring>
#include<cmath>
#include<vector>
#include<map>
#include<queue>
#include<algorithm>
typedef long long ll;
typedef long double ld;
typedef double db;
#define io_opt ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
const int mod=1e9+7;
inline int mo(ll a,int p){
return a>=p?a%p:a;
}
inline int rd() {
int x = 0, f = 1;
char ch;
while (ch < '0' || ch > '9') {
if (ch == '-')f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + ch - '0';
ch = getchar();
}
return f * x;
}
inline ll gcd(ll x, ll y){
return y==0?x:gcd(y,x%y);
}
inline ll speed(ll a,ll b,int p){
ll cur=a,anss=1;
while(b){
if(b&1) anss=anss*cur%p;
cur=cur*cur%p;
b>>=1;
}
return anss%p;
}
const int MAXN=1e5;
bool ipr[MAXN+20];
int cnt,pri[MAXN/5];
void prime(){//埃式筛法
int N=sqrt(MAXN)+0.5,mul;
memset(ipr,true,sizeof(ipr));
ipr[1]=false;
for(int i=2;i<=N;i++){
if(ipr[i]){
i==2?mul=1:mul=2;
for(int j=i*i;j<=MAXN;j+=i*mul){
ipr[j]=false;
}
}
}
for(int i=2;i<=MAXN;i++){
if(ipr[i]){
pri[++cnt]=i;
}
}
}
ll sg[100020];
ll fg[10020];
int gn1(ll x){
int ret=0;
while(x){
ret++;
x=x&(x-1);
}
return ret;
}
void dfs(int mx,int dep,int sum){
if(dep==0){
fg[sum]=1;
return;
}
for(int i=0;i<=mx;i++){
dfs(i,dep-1,sum^sg[i]);
}
}
void getsg(int n=300){
for(int i=2;i<=n;i++){
memset(fg,0,sizeof(fg));
fg[sg[i-1]]=1;
for(int j=2;j<i;j++){
if(i%j==0){
fg[sg[i/j]]=1;
/*if(j%2){
fg[sg[i/j]]=1;
}
else{
fg[0]=1;
}*/
}
}
for(int j=0;;j++){
if(!fg[j]){
sg[i]=j;
break;
}
}
}
}
int n;
bool fun(int x){
if(x==1) return true;
if(x<=MAXN) return ipr[x];
for(int i=1;i<=cnt&&pri[i]*pri[i]<=x;i++){
if(x%pri[i]==0) return false;
}
return true;
}
int main(){
prime();
int T;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
if(n==0||n==16||n==34||n==289){
printf("NIE\n");
}
else if(n==2||n==17){
printf("TAK\n");
}
else if(fun(n)){
printf("NIE\n");
}
else{
printf("TAK\n");
}
}
/*sg[1]=0;
getsg();
for(int i=1;i<=300;i++){
if(sg[i]==0) cout<<i<<endl;
}*/
return 0;
}