hdu 4664 Triangulation(题意已在讨论版中说明)
题意:
给定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函数:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<stdio.h> #include<string.h> #define N 1000 int sg[N]; int GetSG(int k) { if(sg[k]!=-1)return sg[k]; bool mex[N]={0}; for(int i = 0; i <= k-2; i++) { sg[i] = GetSG(i); sg[k-i-2] = GetSG(k-i-2); mex[sg[i]^sg[k-i-2]]=1; } int i=0; while(mex[i])i++; return sg[k]=i; } int main() { int i,j; int t,n,x,ans; memset(sg,-1,sizeof(sg)); GetSG(90); scanf("%d",&t); while(t--) { ans=0; scanf("%d",&n); for(i=0;i<n;i++) { scanf("%d",&x); if(x>86)ans^=sg[(x-53)%34+53]; else ans^=sg[x]; } if(ans)printf("Carol\n"); else printf("Dave\n"); } return 0; }
循环求SG
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<stdio.h> #include<string.h> #define N 1000 int sg[N]; int hash[N]; void GetSG(int n) { int i,j,k; sg[0]=0; sg[1]=0; for(i=2;i<=n;i++) { memset(hash,0,sizeof(hash)); for(j=0;i>=2+j&&j<=i/2;j++) hash[sg[j]^sg[i-2-j]]=1; for(j=0;j<=n;j++) { if(!hash[j]) { sg[i]=j; break; } } } } int main() { int i,j; int t,n,x,ans; GetSG(200);//改成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=0; scanf("%d",&n); for(i=0;i<n;i++) { scanf("%d",&x); if(x>86)ans^=sg[(x-53)%34+53]; 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 0; }