[hdu7022]Jsljgame
先考虑$x=y$的情况,此时即是一个平等博弈,因此考虑$sg$函数
具体的,有$sg(n)=\begin{cases}0&(n=0)\\mex(\{sg(n-i)\mid 1\le i\le n,i\ne x\})&(n\ge 1)\end{cases}$,简单计算$sg(n)$的前几项,不难发现规律$sg(n)=\lfloor\frac{n}{2x}\rfloor x+n\ mod\ x$,进而将其异或即可
(若异或和为0则先手必败,否则先手必胜)
接下来,不妨假设$x>y$且$a_{1}\le a_{2}\le ...\le a_{n}$,此时再分类讨论:
1.若$a_{n}<y$,显然限制没有意义,仍是一个平等博弈,并且有$sg(n)=n$
2.若$a_{n}\ge y$,此时先手必胜,证明如下——
对其进行归纳($n$和$\{a_{i}\}$的字典序),并对此分类讨论:
1.若$n=1$或$a_{n-1}<y$,则总存在$(i,z)$满足$1\le i\le n$且$0\le z<a_{i}$,使得若$a_{i}=z$则$\bigoplus_{i=1}^{n}a_{i}=0$,那么再对$(i,z)$分类讨论——
a.若$1\le i<n$或$i=n$且$z\ne a_{n}-x$,那么将第$i$堆取到$z$个
b.若$i=n$且$z=a_{n}-x$,那么将第$n$堆取到$z+y$个
不论是哪一种情况,后手操作后若$a_{n}\ge y$由归纳假设先手必胜,否则必然异或和非0(第一种情况异或和初始为0且必然变化,第二种情况只能在第$n$堆中取$y$个)同样先手必胜
2.若$n\ge 2$且$a_{n-1}\ge y$,再分类讨论:
a.若$n\ge 3$或$a_{n}>y$,那么先手只需要在第$n-2$或第$n$堆中取一个,后手不可能同时使$a_{n-1},a_{n}<y$,那么由归纳假设先手必胜
b.若$n=2$且$a_{n}=y(=a_{n-1})$,那么先手只需要取完第$n-1$堆,之后后手不能取完第$n$堆,后手操作后先手再取完第$n$堆即可
类似地,对于$x<y$的情况,再分类讨论:
1.若$a_{n}<x$,同样为$sg(n)=n$的平等博弈
2.若$a_{n}\ge x$,此时先手操作后必然要使$\max_{i=1}^{n}a_{i}<x$(否则由之前的结论后手必胜),那么也即是要$n=1$或$a_{n-1}<x$,进而要保证异或和为0,即要求$S<x$且$S\ne a_{n}-x$(其中$S=\bigoplus_{i=1}^{n-1}a_{i}$)
综上,时间复杂度为$o(n\log n)$(排序),可以通过
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 1005 4 int t,n,x,y,ans,a[N]; 5 int main(){ 6 scanf("%d",&t); 7 while (t--){ 8 scanf("%d%d%d",&n,&x,&y); 9 for(int i=1;i<=n;i++)scanf("%d",&a[i]); 10 ans=0; 11 if (x==y){ 12 for(int i=1;i<=n;i++)ans^=a[i]/(x<<1)*x+a[i]%x; 13 if (ans)printf("Jslj\n"); 14 else printf("yygqPenguin\n"); 15 continue; 16 } 17 sort(a+1,a+n+1); 18 if (a[n]<min(x,y)){ 19 for(int i=1;i<=n;i++)ans^=a[i]; 20 if (ans)printf("Jslj\n"); 21 else printf("yygqPenguin\n"); 22 continue; 23 } 24 if (x>y)printf("Jslj\n"); 25 else{ 26 if ((n==1)||(a[n-1]<x)){ 27 for(int i=1;i<n;i++)ans^=a[i]; 28 if ((ans<x)&&(ans!=a[n]-x))printf("Jslj\n"); 29 else printf("yygqPenguin\n"); 30 } 31 else printf("yygqPenguin\n"); 32 } 33 } 34 return 0; 35 }