转载请注明出处,谢谢 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; }