Description
Alice 和 Bob 总喜欢聚在一起玩游戏(T_T),今天他(她)们玩的是一款新型的取石子游戏。游戏一开始有N堆石子,Alice 和 Bob 轮流取出石子。在每次操作中,游戏者必须选择其中的一堆石子,并作出下列的其中一种操作:
- 移去整堆石子
- 假设石子堆中有X颗石子,取出Y颗石子,其中1<=Y
游戏结束的条件是:取出最后一颗石子的人胜出。众所周知,Alice和Bob都是绝顶聪明的,假设他们在游戏中都采取最优的策略,问最后谁会胜出游戏呢?
Alice先取。
20%的数据,N<=5,每堆石子数量少于10
100%的数据,T<=100,N<=100,每堆石子数量不大于1,000,000
Solution
每堆石子互不影响,那么可以分别求出sg函数。暴力求sg的话是会T的,考虑怎么快速求
当x为质数时,所有不大于x的非负整数都能取到,那么sg(x)=max{sg(i)}+1
当x为合数时,设t为x的一个最小质因数,sg(x)=sg(t)
这样记录一下每个数的最小质因数,就能类似筛质数一样筛sg函数惹
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define drp(i,st,ed) for (int i=st;i>=ed;--i)
#define fill(x,t) memset(x,t,sizeof(x))
const int N=1000005;
int sg[N],rec[N],id;
int r[N];
int gcd(int x,int y) {
return !y?x:gcd(y,x%y);
}
void pre_work() {
r[1]=1;
rep(i,2,N-1) {
if (r[i]) continue;
r[i]=i;
for (int j=i;j<=N-1;j+=i) {
if (!r[j]) r[j]=i;
}
}
int mx=0;
rep(i,1,N-1) {
if (r[i]==i) sg[i]=mx+1;
else sg[i]=sg[r[i]];
mx=std:: max(mx,sg[i]);
}
}
int main(void) {
freopen("stone0.in","r",stdin);
freopen("myp.out","w",stdout);
pre_work();
int T; scanf("%d",&T);
while (T--) {
int n; scanf("%d",&n);
int sum=0;
rep(i,1,n) {
int x; scanf("%d",&x);
sum^=sg[x];
}
if (sum) puts("Alice");
else puts("Bob");
}
return 0;
}