1. 程式人生 > >Marbles(Sg函式,終態為必勝態)

Marbles(Sg函式,終態為必勝態)

題意:

有多個點(x,y)(x>0,y>0),雙方可以移動一個點到(xa,y),(x,ya),(xa,ya)(x-a,y),(x,y-a),(x-a,y-a),第一個移到(0,0)(0,0)的玩家獲勝,多個點可以重複,穿越。

解析:

首先是Sg函式,這個沒有問題。但是這道題有點不同,雖然(0,0)(0,0)是必敗態,但是(0,x)(x,0)(x,x)(0,x)(x,0)(x,x)都是必勝態,顯然其他地方只能走到這三種必勝態。

將這些狀態看成終態(此狀態直接決定勝負),但是此時終態為勝態(平時終態為敗態)

我們需要消除這些勝態的影響:將Sg值變為inf

當然,我們最後算異或的時候,如果有一個為終態,直接輸出“Y”即可

#include<bits/stdc++.h>
using namespace std;
int read(){ int ans=0; char last=' ',ch=getchar();
while(ch<'0' || ch>'9')last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}

int sg[109]
[109]; bool vis[200]; void init(){ memset(sg,0,sizeof(sg)); for(int i=0;i<=100;i++)sg[i][i]=sg[i][0]=sg[0][i]=199; for(int i=0;i<=100;i++){ for(int j=0;j<=100;j++){ if(i==j||i==0||j==0)continue; memset(vis,0,sizeof(vis)); for(int a=0;a<i;a++)vis[sg[a]
[j]]=1; for(int b=0;b<j;b++)vis[sg[i][b]]=1; int ti=i-1,tj=j-1; while(min(ti,tj)>=0){ vis[sg[ti][tj]]=1; ti--,tj--; } for(int k=0;;k++){ if(!vis[k]){sg[i][j]=k;break;} } } } } int main(){ init(); int n;scanf("%d",&n); int Nim=0; for(int i=1;i<=n;i++){ int a,b; scanf("%d%d",&a,&b); if(a==b)return 0*printf("Y\n"); Nim^=sg[a][b]; } if(Nim!=0)printf("Y\n"); else printf("N\n"); }