题目描述
Description
Furlo and Rublo play a game. The table has n piles of coins lying on it, the i-th pile has $a_i$ coins. Furlo and Rublo move in turns, Furlo moves first. In one move you are allowed to:
- choose some pile, let’s denote the current number of coins in it as x;
- choose some integer y($0 ≤ y < x$; $x^{1/4} ≤ y ≤ x^{1/2}$) and decrease the number of coins in this pile to y. In other words, after the described move the pile will have y coins left.
The player who can’t make a move, loses.
Your task is to find out, who wins in the given game if both Furlo and Rublo play optimally well.
Input
The first line contains integer n(1 ≤ n ≤ 77777) — the number of piles. The next line contains n integers $a_1$, $a_2$, …, $a_n$(1 ≤ $a_i$ ≤ 777777777777) — the sizes of piles. The numbers are separated by single spaces.
Please, do not use the %lld specifier to read or write 64-bit integers in С++. It is preferred to use the cin, cout streams or the %I64d specifier.
Output
If both players play optimally well and Furlo wins, print “Furlo”, otherwise print “Rublo”. Print the answers without the quotes.
Sample test(s)
| input |
|---|
| 1 |
| 1 |
| output |
|---|
| Rublo |
| input |
|---|
| 2 |
| 1 2 |
| output |
|---|
| Rublo |
| input |
|---|
| 10 |
| 1 2 3 4 5 6 7 8 9 10 |
| output |
|---|
| Furlo |
题目链接
http://codeforces.com/problemset/problem/255/E
解题思路
题目大意:两个人人轮流从N堆石子中取石子,设某一堆得石子数量为x,必须把这堆石子拿到剩下y个,$x^{1/4}<=y<=x^{1/2}$,不能拿得输。
解题思路:这道题和尼姆博弈非常的相似,我们需要寻找必败态。很容易想到,当这一堆得石子剩余1,2,3得时候,此时先手必输。对于石子数量大于大于3的堆,我们需要通过前面的状态来求得后续的状态。
例如,这一堆有4个石子的时候,我们可以取的y值是2,那么我们可以拿走的石子的数量就是2,因此当x = 4的时候,sg[4] = mex(sg[2])。这里的mex(A)函数是一个作用于集合A上的函数,意义是找到一个不在A集合中的最小的自然数。由于sg[2] = 0,因此sg[4] = mex(sg[2]) = 1;
当x = 5的时候,我们可以取的y值是2,因此sg[5] = mex(sg[2]) = 1;
当x = 6的时候,我们可以取的y值是2,因此sg[6] = mex(sg[2]) = 1;
……
当x = 16的时候,我们可以取的y值是2,3,4,因此sg[14] = mex(sg[2], sg[3], sg[4]) = 2;
当x = 16的时候,我们可以取的y值是2,3,4,因此sg[14] = mex(sg[2], sg[3], sg[4]) = 2;
……
多求几个元素我们就可以发现这个SG函数的规律了,它是成段出现的,而且段的长度按照指数级别增长。按照这个规律打表,但是数据范围是1 - 777777777777,无法开这么大的数组,因此我们打表的时候我们只需要处理到$10^6$就可以了,因为$10^6$的sg值可以处理到$10^12$左右的数据。但是这个CF题比较坑,数据不多不少恰好超过了$10^12$这个范围,因此我们需要找到那个超大的下标。
因此我们可以模仿前面的规律,来找到极限的数据。我们可以通过打表来找到的最大的数是50626,此时sg[50626] = 3 ,因此我们可以处理小于50626 * 50626这个数的数据了。一旦超出了这个数据,我们的y值取值范围就会改变,会受到3这个sg值的影响,因此我们要寻找的最大的数就是50626 * 50626。
打表求出每一堆的sg值之后,我们就可以依次将这些状态异或起来,如果最后的结果是0,那么就代表的是先手的必败态,如果是一个非0的数,那么就是后手的必败态。
然后附上一个SG打表的函数:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40map<int, int> sg;
bool hash[105];
int getSG(int x)
{
if (x == 1) return 0;
int l = sqrt(sqrt(x)), r = sqrt(x);
if (l * l * l * l != x) l++;
memset(hash, false, sizeof(hash));
for (int i = l; i <= r; i++)
{
hash[sg[i]] = true;
}
for (int i = 0; i <= 100; i++)
{
if (!hash[i]) return i;
}
}
void init()
{
sg[0] = 0;
for (int i = 1; i <= 100000; i++)
{
sg[i] = getSG(i);
}
for (int i = 1; i <= 100000; i++)
{
if (sg[i] != sg[i - 1])
printf("sg[%d] = %d\n", i, sg[i]);
}
}
/*
sg[4] = 1
sg[16] = 2
sg[82] = 0
sg[6724] = 3
sg[50626] = 1
sg[2562991876] = 2
*/
AC代码
4 KB/62 ms/GNU G++ 4.9.21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
int main()
{
int n;
while (~scanf("%d", &n))
{
long long x;
int ans = 0;
for (int i = 0; i < n; i++)
{
scanf("%I64d", &x);
if (x < 4) ans ^= 0;
else if (x < 16) ans ^= 1;
else if (x < 82) ans ^= 2;
else if (x < 6724) ans ^= 0;
else if (x < 50626) ans ^= 3;
else if (x < 2562991876LL) ans ^= 1;
else ans ^= 2;
}
if (ans) puts("Furlo");
else puts("Rublo");
}
return 0;
}