C. C. Blog

Security Research, Algorithm and Data Structure

51Nod 1831 小C的游戏

Problem

小C和小L是好朋友,她们在玩一个游戏。 一开始有一个大小为n的石子堆,小C先手。 每次可以对这个石子堆拿走一个或者把这个石子堆分成等量的几份并只取其中一份(不能不变或只剩下一个)。 如果取走最后一个人的算败,请问这个游戏小C是否能胜。

Solution

SG打表,总体上是质数败,但有几个不一样的。

注意sg[1]=0,从sg[2]开始计算。

不需要算奇偶个异或,题目的意思是取出一份来,用这一份继续游戏。

最简单的做法就是找规律了,直接搜一下就能获得所有的胜负态。 仔细观察可以发现质数除了2和17就是败的,合数除了16,34和289都是赢的。 感觉这样是不太科学的,那就来讲讲道理。 我们发现2,4,8都是赢的,而16的后继状态都是赢的,所以它是败的,而2n(n>4)都能转化到16。 同样的我们能说明17和2n17^m。 我们考虑一个合数,它的因数肯定有个败态的,它就必胜了。 这样也就说明了质数是必败了。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#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;
}


  • 本文作者: CCWUCMCTS
  • 本文链接: https://ccwucmcts.github.io/posts/17483/
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!