您的位置:首页 > 其它

A Game Between Alice and Bob(zoj 3529)

2014-04-27 18:47 483 查看
题目戳这里

题目大意是:给你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
= 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
= 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
= sum,就变成sg[1] ^ sg[2] ^…… ^sg[i] ^sum……sg
= 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
!= -1)
return sg
;
int i;
if(prime
== 0)
return sg
= 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 = 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;
}
}
else
printf("Bob\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: