题目链接:http://codeforces.com/problemset/problem/768/E
NIM游戏改版:对于任意一堆,拿掉某个次数最多只能一次。
对于一堆石头数量为$X$。找到一个最小的$Z$使得${ (sum_{i=1}^{Z}i)leq x}$,我们把这一堆数量为X的石头,看作Z个数目分别为${1...n}$的石头堆。
那么一次拿一定量的石头,是不是相当于拿走了${{1,2,3....,Z}}$中的任意多堆石头?
当然如果拿的石头数目$P$超过了${sum _{i=1}^{Z}i}$,相当于拿走了所有大于${{Z}'}$的的石头堆。${{Z}'=Maxleft { val|(sum _{i=1}^{val}i)leq (X-P) ight }}$
所以${SG(X)=Max(Z|(sum_{i=1}^{Z}i)leq X)}$
很显然,这是一个multi-nim游戏,主游戏的SG值等于所有子游戏的异或和。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<vector> 5 #include<cstdlib> 6 #include<cmath> 7 #include<cstring> 8 using namespace std; 9 #define maxn 10010 10 #define llg long long 11 #define yyj(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout); 12 llg n,m,x,v; 13 14 llg make_sg(llg x) 15 { 16 if (x==0) return 0; 17 llg l=0,r=(llg)1e9,val; 18 while (l<=r) 19 { 20 llg mid=(l+r)>>1; 21 if ((mid*mid+mid)/2<=x) {l=mid+1; val=mid;}else r=mid-1; 22 } 23 return val; 24 } 25 26 int main() 27 { 28 yyj("SG"); 29 cin>>n; 30 31 for (llg i=1;i<=n;i++) 32 { 33 scanf("%lld",&v); 34 x^=make_sg(v); 35 } 36 if (!x) cout<<"YES";else cout<<"NO"; 37 return 0; 38 }