吉林大學ACM集訓隊選拔賽 K題 Dress as women

題目描述

nn 個點,兩個人輪流去掉一些點,每次去掉的點必須共線,無法操作的人輸,問先手必勝還是必敗

題解

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");
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章