方法: SG函数
解析:挺有思维量的题?不要D我
这道题关键在于局面与子游戏的把握。如何定义这道题的局面呢?
想了半个小时没有想出来,因为毕竟如果令石子数的话是会与其他游戏产生干扰的。
然后看了某神犇的题解?定义局面:一颗豆子在i位置处。
一下子恍然大悟啊,YY一下就AC了。
现在考虑一个局面:一颗豆子在i位置。
会有什么子游戏呢?会转移到一颗豆子在j位置以及一颗豆子在k位置。
而一颗豆子在i位置时的sg[i]怎么算呢?就是其所有子游戏的mex运算。而子游戏是什么呢?是一颗豆子在j以及一颗豆子在k两个子局面的异或和。所以我们能算出sg[i]。
假设i这个位置有一堆豆子,那我们需要将sg[i]异或一堆遍。所以可以有一个优化,一个位置的豆子数为奇数时,只需要异或一次,为偶数时不需要异或。
n的范围小的令人发指,所以我们可以枚举第一步。
第一步过后能使得总局面的sg值为0的话即我们操作之后对于另一人来说,该人必败,统计一下方案数就OK了。
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 25
#define M 10010
using namespace std;
int a[N];
int ssgg[N];
int t,n;
int sg(int x)
{
if(x==n)return 0;
if(ssgg[x]!=-1)return ssgg[x];
int v[M];
memset(v,0,sizeof(v));
for(int i=x+1;i<=n;i++)
{
for(int j=i;j<=n;j++)
{
v[sg(i)^sg(j)]=1;
}
}
for(int i=0;;i++)if(!v[i])return ssgg[x]=i;
}
int ai,bi,ci;
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
memset(ssgg,-1,sizeof(ssgg));
int tmp=sg(1);ssgg[n]=0;
int cnt=0;
for(int i=1;i<=n;i++)
{
if(a[i]!=0)
{
for(int j=i+1;j<=n;j++)
{
for(int k=j;k<=n;k++)
{
a[i]--,a[j]++,a[k]++;
int ans=0;
for(int l=1;l<=n;l++)
{
if(a[l]&1)
ans^=ssgg[l];
}
if(ans==0)
{
cnt++;
if(cnt==1)
{
printf("%d %d %d\n",i-1,j-1,k-1);
}
}
a[i]++,a[j]--,a[k]--;
}
}
}
}
if(!cnt)printf("-1 -1 -1\n");
printf("%d\n",cnt);
}
}