题目描述
n n n 个点,两个人轮流去掉一些点,每次去掉的点必须共线,无法操作的人输,问先手必胜还是必败
题解
sg函数题目,没有点的局面是必败态,需要求其他状态的sg值
状态转移时,需要判断两个状态转移合法,即判断去掉的点是否共线
先用dfs将所有共线的局面搜索出来
然后是枚举子集和sg函数求法的套路了
#include<bits/stdc++.h>
#define N 300010
#define INF 0x3f3f3f3f
#define eps 1e-8
#define pi 3.141592653589793
#define mod 998244353
#define P 1000000007
#define LL long long
#define pb push_back
#define fi first
#define se second
#define cl clear
#define si size
#define lb lower_bound
#define ub upper_bound
#define bug(x) cerr<<#x<<" : "<<x<<endl
#define mem(x,y) memset(x,0,sizeof(int)*(y+3))
#define sc(x) scanf("%d",&x)
#define scc(x,y) scanf("%d%d",&x,&y)
#define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;
typedef pair<int,int> pp;
int sg[1<<15],fg[1<<15],lg[1<<15];
int x[20],y[20];
int n;
bool check(int st,int t){
if (lg[st]) return 1;
int a=lg[st&-st];
st-=st&-st;
int b=lg[st&-st];
return 1ll*(y[a]-y[b])*(x[t]-x[b])==1ll*(y[t]-y[b])*(x[a]-x[b]);
}
void goo(int sta,int fa){
if (fg[sta|(1<<fa)]==1) return;
fg[sta|(1<<fa)]=check(sta,fa);
if (!fg[sta]) return;
sta|=1<<fa;
for(int i=0;i<n;i++){
if (sta>>i&1) continue;
goo(sta,i);
}
}
int main(){
for(int i=0;i<15;i++) lg[1<<i]=i;
sc(n);
for(int i=0;i<n;i++) scc(x[i],y[i]);
sg[0]=0;
int up=1<<n;
for (int i=0;i<up;i++) fg[i]=-1;
for(int i=0;i<n;i++) goo(0,i);
for(int i=1;i<up;i++){
bool u[16]={0};
for(int j=i;j;j=(j-1)&i) if (j!=i&&fg[j^i]==1) u[sg[j]]=1;
if (fg[i]==1) u[0]=1;
for(int j=0;;j++) if (!u[j]){
sg[i]=j;break;
}
}
if (sg[up-1]) puts("zyh");else puts("fzj");
}