题目类似于n个堆中取数的游戏,不过由于X的范围太大,我们不能在限定的时间内暴力推出所有的SG函数。不过,我们可以试着找规律,先打出前20的SG表:
X |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
SG(X) |
0 |
1 |
0 |
2 |
1 |
3 |
0 |
4 |
2 |
5 |
1 |
6 |
3 |
7 |
0 |
8 |
4 |
9 |
2 |
10 |
似乎只有X为偶数的规律:SG(X)=X/2。但是当把X为偶数的SG值全部省略后,我们得到的新的列表是和原列表相似的。所以X为奇数时,SG(X)=SG(X/2),n堆的SG值异或一下就可以了,SG = 0先手必败。
X |
1 |
3 |
5 |
7 |
9 |
11 |
13 |
15 |
17 |
19 |
SG(X) |
0 |
0 |
1 |
0 |
2 |
1 |
3 |
0 |
4 |
2 |
1.x为奇数时 令SG(x)=k, 则要想找到一个新的SG(n)使得SG(n)=SG(x)
则SG(n)的求值范围中不能包括SG(x)
n的最小值的方程为: (n+1)/2=x+1 , 解得n=2x+1
故SG(2*k+1)=SG(k)
2.偶数呢?对于一个奇数k, SG(2k+1)=SG(k)=SG((k-1)/2)
2k+1-k=k+1
k-(k-1)/2=(k+1)/2
故每隔一个SG区间, SG区间中的数会增加一倍, 这和下标的的偶数数量正好相同
故每个偶数k, 其SG(k)都是一个新数(之前没出现过的)
很快就得到SG(k)=k/2
代码贴上
var i,j,k,l,n:longint; a,m:int64; function sg(a:int64):int64; begin if odd(a) then exit(sg(a div 2)); exit(a div 2); end; begin readln(n); for i:=1 to n do begin read(a); m:=m xor sg(a); end; if m = 0 then writeln('You Are An Apple of My Eyes') else writeln('Lady First'); end.