UVALive - 5059
组合游戏UVALive - 5059
输入n和n个数,n堆石子。每次不能拿超过该堆石子的一半;
二人轮流去,最后没的取的为输。
求SG值;sg(x)=mex(sg(y)|y为x的后继)
这里sg(x)=mex(sg(x-1),sg(x-2)..sg(ceil(x/2)));
sg(1)=0;sg(2)=1;sg(3)=0;sg(4)=2;sg(5)=1
当x为偶数时,mex()中必定有x/2个数,且[0,x/2-1];所以sg(x)=x/2;
当x为奇数时,mex()中有(x-1)/2个数,x-1为偶数,sg(x-1)里也有(x-1)/2个数;
sg(x-1)=mex(sg(x-2),sg(x-3)..sg(x-(x-1)/2-1));
sg(x)=mex(sg(x-1),sg(x-2)..sg(x-(x-1)/2));里面的数都不会重复的。
sg(x-1)必定是最大的。所以sg(x)=sg(x-(x-1)/2-1)),即sg(x)=sg((x-1)/2);
然后像nim游戏异或一下就可以得出结果。。
这题坑爹的是必须得cin,cout输入输出才能对,坑爹的OJ啊。。
提交无数次,最后顶不顺了,看别人AC代码,还是不知道怎么错,然后照着它们来改,最后发现要C++输入输出。。
我是见识太少,还是太坑爹啊。。我都快被它气晕了。。
AC代码:
1 #include<iostream> 2 #define ll long long 3 using namespace std; 4 ll sg(ll x) 5 { 6 if (x&1) return sg(x>>1); 7 return x>>1; 8 } 9 int main () 10 { 11 int t,n; 12 cin>>t; 13 while (--t>=0) 14 { 15 cin>>n; 16 ll num,ans=0; 17 while (--n>=0) 18 { 19 cin>>num; 20 ans^=sg(num); 21 } 22 if (ans) cout<<"YES"<<endl; 23 else cout<<"NO"<<endl; 24 } 25 return 0; 26 }