题意:
给定n个平面(平面之间相互独立),每个平面上有一些点,并且构成凸集,C和D轮流选一个平面连接两个点画线段,并保证线段之间除了端点之外没有其它交点,当平面上出现一个完整的三角形之后此平面就不能继续画线。最早无法画线的人输。输出赢的人。
解法:
因为n个平面是独立的,所以sg函数满足异或的关系。对于每一个平面,求sg值。对于n个点,连上一条线可以分成 i 和 n-2-i 两个独立的部分。所以该点的子状态为sg[i]^sg[n-i-2](0<=i<=n-2)。然后可以计算该点的sg值。打表发现n>68之后会出现长度为34的循环,所以打个34×3的表就可以了。sg函数是个好东西啊!
递归搜索求SG函数:
#include<stdio.h>
#include<string.h>
#define N 1000
int sg[N];
int GetSG(int k)
{
if(sg[k]!=-)return sg[k];
bool mex[N]={};
for(int i = ; i <= k-; i++)
{
sg[i] = GetSG(i);
sg[k-i-] = GetSG(k-i-);
mex[sg[i]^sg[k-i-]]=;
}
int i=;
while(mex[i])i++;
return sg[k]=i;
}
int main()
{
int i,j;
int t,n,x,ans;
memset(sg,-,sizeof(sg));
GetSG();
scanf("%d",&t);
while(t--)
{
ans=;
scanf("%d",&n);
for(i=;i<n;i++)
{
scanf("%d",&x);
if(x>)ans^=sg[(x-)%+];
else ans^=sg[x];
}
if(ans)printf("Carol\n");
else printf("Dave\n");
}
return ;
}
循环求SG
#include<stdio.h>
#include<string.h>
#define N 1000
int sg[N];
int hash[N];
void GetSG(int n)
{
int i,j,k;
sg[]=;
sg[]=;
for(i=;i<=n;i++)
{
memset(hash,,sizeof(hash));
for(j=;i>=+j&&j<=i/;j++)
hash[sg[j]^sg[i--j]]=;
for(j=;j<=n;j++)
{
if(!hash[j])
{
sg[i]=j;
break;
}
}
}
}
int main()
{
int i,j;
int t,n,x,ans;
GetSG();//改成GetSG(90);就WA了,奇葩错误啊
/*
GetSG(200);
for(i=0;i<=200;i++)
{
printf("%d ",sg[i]);
if(i>=52&&(i-52)%34==0)printf("\n");//if(i==52)printf("\n");
}*/
scanf("%d",&t);
while(t--)
{
ans=;
scanf("%d",&n);
for(i=;i<n;i++)
{
scanf("%d",&x);
if(x>)ans^=sg[(x-)%+];
else ans^=sg[x];
/*if(x<86) ans^=sg[x];
else ans^=sg[x%34+68];*/ }
if(ans)printf("Carol\n");
else printf("Dave\n");
}
return ;
}