题意:
给出n堆珠子,每堆有a[i]个;
两个人轮流操作,每次操作都是以下三步:
1.选择n堆中魔法珠数量大于1的任意一堆。记该堆魔法珠的数量为p,p有b1、b2……bm这m个小于p的约数;
2.施展魔法把这一堆魔法珠变成m堆,每堆各有b1、b2……bm颗魔法珠;
3.选择这m堆中的一堆魔法珠,施展魔法令其消失;
当有一方不能操作时判负,求先手赢还是后手赢;
题解:
这道题中有很多个堆,但是各个堆中是互不影响的,所以可以利用SG定理合并游戏结果;
那么考虑游戏的结果,当珠子全为1时游戏就结束了;
1就是游戏的终态,SG函数值就是0;
(不知道SG函数的还是右转白书吧(笑))
之后的事就是求SG函数,暴力求约数,递归找约数SG值;
异或在一起之后再枚举一遍,再异或哪个约数就是删掉了那堆;
hash统计一遍就得到了SG函数,本题也就解决了;
注意递归调用的姿势,千万不要将hash数组和约数数组开在全局变量里= = ;
代码:
#include<stdio.h> #include<string.h> #include<algorithm> #define N 1100 using namespace std; int f[N]; int yue_mo(int *yue,int n) { int cnt=0; for(int i=1;i<n;i++) { if(n%i==0) yue[++cnt]=i; } return cnt; } int slove(int n) { if(f[n]!=-1) return f[n]; int yue[n]; bool hash[N<<2]; memset(hash,0,sizeof(hash)); int len=yue_mo(yue,n),k=0; for(int i=1;i<=len;i++) k^=slove(yue[i]); for(int i=1;i<=len;i++) hash[slove(yue[i])^k]=1; for(int i=0;;i++) if(!hash[i]) { f[n]=i; break; } return f[n]; } int main() { int n,m,i,j,k; memset(f,-1,sizeof(f)); f[1]=0; while(scanf("%d",&n)!=EOF) { k=0; for(i=1;i<=n;i++) { scanf("%d",&j); k^=slove(j); } if(k) puts("freda"); else puts("rainbow"); } return 0; }
原文地址:http://blog.csdn.net/ww140142/article/details/47016431