A Game Between Alice and Bob(zoj 3529)

来源:互联网 发布:我爱你用网络语言表达 编辑:程序博客网 时间:2024/05/16 15:17

题目戳这里

题目大意是:给你n个数字,两个人轮流每次选择一个数,将它替换成这个数的一个正因子,但不能是其本身,谁走了某一步之后所有的数都变成1了,那么这个人赢,如果先手赢还要输出第一步替换的数字的位置。

这道题折腾了好一会……刚开始一直超时,先是用常规的SG函数的求法,后来又改成计算数的素因子的个数,但是即使想到这了,因为找素因子的方法不够精到……还是超时……为什么SG值数素因子的个数呢,因为素数的SG值是等于1的,将某个数分解成它的因子,如果这些因子不是素数,那么就还可以再继续往下分,直到所有的因子都是素数,在分的过程中观察SG函数的值,也就可以发现最后这个数的SG值就是所有素因子的个数。

这是超时的找素因子的个数的求法,是从2一个一个开始网上找:

int c = 0, temp = n;for(i = 2; i * i <= n; i++){while(temp % i == 0){c ++;temp /= i;}}if(temp > 1)c ++;return sg[n] = c;



不超时的代码, 其中p数组存储的是从小到大的素数:

int c = 0, temp = n;for(i = 0; i < l && p[i] * p[i] <= n; i++){while(temp % p[i] == 0){c ++;temp /= p[i];}}if(temp > 1)c ++;return sg[n] = c;



还有就是最后输出第一步替换哪一个数字,这实际上就是nim,每个数字是一堆石子,只不过每次能取的石子数目有限制。
现在要求输出第一步选取的石子堆,其实就是在某一堆中拿走一些石子,使得所有石子的异或和是0。
条件就是:sg[i] > sum ^ sg[i],sum ^ sg[i]是除去i这一堆的石子数的异或和,如果sg[i] > sum ^ sg[i],那么第 i 堆石子就可以拿走若干个使之变成 sum ^ sg[i],这样原本的sg[1] ^ sg[2] ^…… ^sg[i] ^……sg[n]  = sum,就变成sg[1] ^ sg[2] ^…… ^sg[i] ^sum……sg[n]  = sum ^ sum = 0。这样,就将所有的数的SG值的异或和变成0,就把失败态留给对方。

#include <stdio.h>#include <string.h>int sg[5000050];bool prime[5000050];int p[5000000], l = 0;int num[100100];void isprime(){int i, j;prime[1] = prime[0] = 1;for(i = 2; i * i < 5000010; i++){if(!prime[i]){p[l ++] = i;for(j = i + i; j < 5000010; j += i)prime[j] = 1;}}}int getsg(int n){if(sg[n] != -1)return sg[n];int i;if(prime[n] == 0)return sg[n] = 1;/*bool hash[1000];memset(hash, 0, sizeof(hash));for(i = n - 1; i * i >= n; i--) if(n % i == 0){hash[getsg(i)] = 1;hash[getsg(n / i)] = 1;}for(i = 1; i < 1000; i++)if(hash[i] == 0)break;*/int c = 0, temp = n;for(i = 0; i < l && p[i] * p[i] <= n; i++){while(temp % p[i] == 0){c ++;temp /= p[i];}}if(temp > 1)c ++;return sg[n] = c;}int main (void){isprime();memset(sg, -1, sizeof(sg));int i;sg[0] = sg[1] = 0;int n, c = 0;while(scanf("%d", &n) != EOF){c ++;int sum = 0;for(i = 0; i < n; i++){scanf("%d", &num[i]);sum ^= getsg(num[i]);}printf("Test #%d: ", c);if(sum){printf("Alice ");for(i = 0; i < n; i++)if(sg[num[i]] > (sum ^ sg[num[i]])){printf("%d\n", i + 1);break;}}elseprintf("Bob\n");}return 0;}





0 0
原创粉丝点击