转载请注明出处,谢谢 http://blog.csdn.net/ACM_cxlove?viewmode=contents by---cxlove
题意:有N堆石头,每次选中某一堆,把数量替换成原先的因子。全部为1则结束。
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4464
乍一看,SG博弈,一个状态的后继就是所有因子,然后MEX操作,果断TLE。不过思想还算正确。
以下为TLE代码
#include<iostream>
#include<cstdio>
#include<ctime>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<vector>
#define C 240
#define TIME 10
#define inf 1<<25
#define LL long long
using namespace std;
int sg[5000005];
int get_sg(int n){
if(sg[n]!=-1)
return sg[n];
int vis[1005];
memset(vis,0,sizeof(vis));
vis[0]=1;
for(int i=2;i*i<=n;i++){
if(n%i==0){
vis[get_sg(i)]=1;
vis[get_sg(n/i)]=1;
}
}
for(int i=0;;i++)
if(vis[i]==0)
return sg[n]=i;
}
int main(){
int n,cas=0,a[100005];
memset(sg,-1,sizeof(sg));
sg[1]=0;
for(int i=5000000;i;i--){
if(sg[i]==-1)
get_sg(i);
}
while(scanf("%d",&n)!=EOF){
int ret=0;
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
ret^=sg[a[i]];
}
printf("Test #%d: ",++cas);
if(ret==0) puts("Bob");
else{
printf("Alice ");
for(int i=0;i<n;i++){
if(a[i]>(ret^sg[a[i]])){
printf("%d\n",i+1);
break;
}
}
}
}
return 0;
}
仔细分析,对于某一个数,他的后继有多少个呢,其实就是质因子的个数。
比如说12,他的后继有6,4,2这3个。正好是他的质因子个数,2,2,3。相当于NIM游戏中,3个石头,每次可以拿走1-3个。
那我们打出素数表,然后暴力求出质因子个数就行了,也可以DP预处理质因子个数。
转换成NIM之后,考虑必胜的第一步策略。同样还是NIM一样。转换成拿走几个因子。
#include<iostream>
#include<cstdio>
#include<ctime>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<vector>
#define C 240
#define TIME 10
#define inf 1<<25
#define LL long long
using namespace std;
bool flag[5000005]={0};
int cnt=0,prime[5000000];
int sg[5000005];
void Prime(){
// prime[cnt++]=1;
for(int i=2;i<=sqrt(1.0+5000000);i++){
if(flag[i]) continue;
prime[cnt++]=i;
sg[i]=1;
for(int j=2;j*i<=sqrt(1.0+5000000);j++)
flag[i*j]=true;
}
}
int get_sg(int n){
if(sg[n]!=-1) return sg[n];
int k=0,t=n;
for(int i=0;i<cnt&&prime[i]*prime[i]<=n;i++)
if(n%prime[i]==0){
while(n%prime[i]==0){
k++;
n/=prime[i];
}
}
if(n>1)
k++;
return sg[t]=k;
}
int main(){
memset(sg,-1,sizeof(sg));
sg[1]=0;
Prime();
int n,cas=0,a[100000];
while(scanf("%d",&n)!=EOF){
int ret=0;
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
ret^=get_sg(a[i]);
}
printf("Test #%d: ",++cas);
if(ret==0) puts("Bob");
else{
printf("Alice ");
for(int i=0;i<n;i++)
if(sg[a[i]]>(ret^sg[a[i]])){
printf("%d\n",i+1);
break;
}
}
}
return 0;
}