小C和小L是好朋友,她们在玩一个游戏。
一开始有一个大小为n的石子堆,小C先手。
每次可以对这个石子堆拿走一个或者把这个石子堆分成等量的几份并只取其中一份(不能不变或只剩下一个)。
如果取走最后一个人的算败,请问这个游戏小C是否能胜。
一开始有一个大小为n的石子堆,小C先手。
每次可以对这个石子堆拿走一个或者把这个石子堆分成等量的几份并只取其中一份(不能不变或只剩下一个)。
如果取走最后一个人的算败,请问这个游戏小C是否能胜。
Input
一行表示数据组数Tcases(Tcases<=1,000)。 后面Tcases行每行一个n(n<=1,000,000,000)。
Output
有Tcases行对于先手获胜输出“TAK”,先手狗带输出“NIE”。
Input示例
1 5
Output示例
NIE
贴一份官方题解:
最简单的做法就是找规律了,直接搜一下就能获得所有的胜负态。
仔细观察可以发现质数除了2和17就是败的,合数除了16,34和289都是赢的。
感觉这样是不太科学的,那就来讲讲道理。
我们发现2,4,8都是赢的,而16的后继状态都是赢的,所以它是败的,而2^n(n>4)都能转化到16。
同样的我们能说明17和2^n17^m。
我们考虑一个合数,它的因数肯定有个败态的,它就必胜了。
这样也就说明了质数是必败了。
如果打表的话, 茫茫一堆数里找到规律有点难,首先猜结论,可能与质数合数有关,然后打表的时候把质数合数晒出来。。
打表规律代码(附打表代码)
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;
const int maxn = 4e4 + 5;
const int maxx = 3e2 + 5 ;
int dp[maxn], prime[maxn];
void get_data()
{
dp[1] = 0; dp[2] = 1; dp[3] = 0; dp[4] = 1;
dp[5] = 0;
for(int i = 5; i <= maxx; i++)
{
dp[i] = dp[i-1] ? 0 : 1;
for(int j = 2; j < i; j++)
{
if(i%j == 0)
{
if(!dp[j])
{
dp[i] = 1;
break;
}
}
}
}
}
void get_prime()
{
for(int i = 2; i <= maxn; i++)
{
if(!prime[i])
{
for(int j = i*2; j <= maxn; j += i)
prime[j] = 1;
}
}
}
int main()
{
int t, n;
// get_data();
// get_prime();
// for(int i = 1; i <= maxx; i++)
// {
// if(dp[i] && !prime[i])
// {
// cout << "质数 Win" << ' ';
// cout << i << endl;
// }
// else if(!dp[i] && prime[i])
// {
// cout << "合数 Lose" << ' ';
// cout << i << endl;
// }
printf("%5d%s", i, dp[i] ? "WIN " : "LOSE ");
if(i % 5 == 0) cout << endl;
// }
cin >> t;
while(t--)
{
scanf("%d", &n);
int temp = n;
for(int i = 2; i*i <= temp; i++)
{
while(temp%i == 0)
temp /= i;
}
if(temp == n)
{
if(n == 2 || n == 17)
cout << "TAK" << endl;
else
cout << "NIE" << endl;
}
else
{
if(n == 16 || n == 34 || n == 289)
cout << "NIE" << endl;
else
cout << "TAK" << endl;
}
}
return 0;
}
这题虽然是1e9但是我们记忆化到1e7完全可以,大于1e7的让他自己搜就行,而且这个最大复杂度是1e9-1e7,我们只要把搜因子的代码放在-1代码前面,否则会一直-1,-1,-1,就爆栈了。。。这样更快搜出来算一个小优化。。。以后搜索要注意会不会爆栈。。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;
const int maxn = 1e7 + 5;
int dp[maxn];
int dfs(int x)
{
if(x < maxn && dp[x] != -1) return dp[x];
for(int i = 2; i*i <= x; i++)
{
if((x%i == 0) && (!dfs(i) || !dfs(x/i)))
{
if(x < maxn) return dp[x] = 1;
else return 1;
}
}
if(!dfs(x-1)) //这里一定要放在后面
{
if(x < maxn)
return dp[x] = 1;
else
return 1;
}
if(x < maxn)
return dp[x] = 0;
else
return 0;
}
int main()
{
int t, n;
memset(dp, -1, sizeof(dp));
dp[0] = 0; dp[1] = 0; dp[2] = 1; dp[3] = 0;
cin >> t;
while(t--)
{
scanf("%d", &n);
if(dfs(n))
cout << "TAK" << endl;
else
cout << "NIE" << endl;
}
return 0;
}