由于有多条链,每条链可以单独作为一个游戏,最后把sg值亦或起来就可以判断胜负。
对于每条链,选定第k个后,会分成若干条链,每条链可以递归的求sg值。
选择某个ring之后分成若干条链,是走了一步,这些链的sg值应该亦或起来,作为选择某个ring之后得到的sg值。
由于选择不同的ring会有不同的结果,所以选择不同的ring得到的sg值应该保存起来,然后原链的sg值去最小未出现sg值就行。
这题的重点在于要给出第一步的位置。
首先已知所有链亦或后的sg值,也就是判断胜负的as。
对于每一条链,先用as亦或该链的sg值,相当于抛出去该链。
然后对于该链,枚举每一个ring的位置,得到该位置的sg值tmp。
如果tmp^as==0,代表该位置是使得后手必胜的位置,也就得到答案。
最后别忘了as亦或该链的sg值,相当于在结果中包括该链。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int dp[60][110][110]; int a[60][110],id; int s[110],top; void dfs(int l,int r){ int &as=dp[id][l][r]; if(as!=-1)return ; as=0; if(l>r)return ; int i,k,st,ed,sg; for(k=l;k<=r;k++){ st=-1; for(i=l;i<=r;i++){ if(a[id][i]<=a[id][k]&&st!=-1){ ed=i-1; dfs(st,ed); st=-1; } if(a[id][i]>a[id][k]&&st==-1) st=i; } if(st!=-1){ ed=i-1; dfs(st,ed); st=-1; } } top=0; for(k=l;k<=r;k++){ st=-1; sg=0; for(i=l;i<=r;i++){ if(a[id][i]>a[id][k]&&st==-1) st=i; if(a[id][i]<=a[id][k]&&st!=-1){ ed=i-1; sg^=dp[id][st][ed]; st=-1; } } if(st!=-1){ ed=i-1; sg^=dp[id][st][ed]; st=-1; } s[top++]=sg; } sort(s,s+top); top=unique(s,s+top)-s; for(i=0;i<top;i++) if(s[i]==as) as++; else break; } int main(){ int i,j,k,n,m,as=0; int tmp,st,ed; memset(dp,-1,sizeof(dp)); scanf("%d",&n); for(id=1;id<=n;id++){ scanf("%d",&m); for(i=1;i<=m;i++) scanf("%d",&a[id][i]); a[id][0]=m; dfs(1,m); as^=dp[id][1][m]; } if(as==0){puts("S");return 0;} for(id=1;id<=n;id++){ m=a[id][0]; as^=dp[id][1][m]; for(k=1;k<=m;k++){ tmp=0; st=-1; for(i=1;i<=m;i++){ if(a[id][i]>a[id][k]&&st==-1) st=i; if(a[id][i]<=a[id][k]&&st!=-1){ ed=i-1; tmp^=dp[id][st][ed]; st=-1; } } if(st!=-1){ ed=i-1; tmp^=dp[id][st][ed]; st=-1; } if((as^tmp)==0)break; } as^=dp[id][1][m]; if(k<=m)break; } printf("G\n%d %d\n",id,k); return 0; }