吉林大学ACM集训队选拔赛 K题 Dress as women

题目描述

n n n 个点,两个人轮流去掉一些点,每次去掉的点必须共线,无法操作的人输,问先手必胜还是必败

题解

sg函数题目,没有点的局面是必败态,需要求其他状态的sg值
状态转移时,需要判断两个状态转移合法,即判断去掉的点是否共线
先用dfs将所有共线的局面搜索出来
然后是枚举子集和sg函数求法的套路了

#include
#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<<"      :   "<
#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");
}

你可能感兴趣的:(博弈)