题目大意:
有n个碗里面装了ai粒糖果,然后每次一个人可以选择一组 i<j≤k i < j ≤ k 然后把第i和碗里面的糖果个数-1,后面两个碗里的糖果数量+1,到最后操作不了的人便输了。
思路:
这题的思路是真的巧妙,不愧是我大HNOI的题目。。。
发现满足不了条件只有一种情况,就是所有的糖果都在最后一个碗里面。但是SG函数的使用必须要有一个确定的状态,我们不可能去把每一个碗里面的每一种状态都记下来,这不现实。
然后就是这题的巧妙之处了,我们将每一个糖果看作一个单独的游戏,就是将这个糖果从第i个位置移动到第n个位置,其实也就是一堆个数为
n−i
n
−
i
的石子等你来取。
如果每一次只增加一个糖果的话就很好办了,但是是这是增加了两个糖果,相当于增加了又新加了一堆石子。换一个角度去想,新加的这一堆石子反正最后总是要取走的,转移后的状态便是后面两个糖果所构成的游戏的和。数据这么小,上SG就完事了。
/*======================
* Auhtor : ylsoi
* Problem : bzoj1188
* Algorithm : SG
* Time : 2018.6.2
*=====================*/
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<climits>
using namespace std;
void File(){
freopen("bzoj1188.in","r",stdin);
freopen("bzoj1188.out","w",stdout);
}
#define REP(i,a,b) for(register int i=a;i<=b;++i)
#define DREP(i,a,b) for(register int i=a;i>=b;--i)
#define MREP(i,x) for(register int i=beg[x];i;i=E[i].last)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define inf INT_MAX
const int maxn=21+10;
const int maxm=10000+10;
int T,n,a[maxn],SG[maxn],ans;
bool in[maxm];
int main(){
File();
SG[0]=0;
REP(i,1,21){
mem(in);
REP(j,0,i-1)REP(k,j,i-1){
in[SG[j]^SG[k]]=1;
}
REP(j,0,21*21)if(!in[j]){
SG[i]=j;
break;
}
}
scanf("%d",&T);
while(T--){
scanf("%d",&n);
REP(i,1,n)scanf("%d",&a[i]);
ans=0;
REP(i,1,n)if(a[i]%2)
ans^=SG[n-i];
if(!ans)puts("-1 -1 -1\n0");
else{
int cnt=0,ti,tj,tk,flag=0;
REP(i,1,n)REP(j,i+1,n)REP(k,j,n){
if((ans^SG[n-i]^SG[n-j]^SG[n-k])==0){
++cnt;
if(!flag)ti=i-1,tj=j-1,tk=k-1,flag=1;
}
}
printf("%d %d %d\n",ti,tj,tk);
printf("%d\n",cnt);
}
}
return 0;
}