题目:
其实就是在nim游戏基础上添加了一次可以不取的机会。
多堆石子可以看成多个游戏,它们起点的sg值异或起来就是整个游戏的sg值,若sg值为1,则先手必胜,为0,则后手必胜。
关键在于怎么求sg值:可以打表找规律->对游戏局面进行动态dfs连边,再dfs一遍求sg值(也就是求mex值)
细节:dfs能跑到的范围很小,最多到20(可能还达不到,因为边实在是太多了),所以死循环时不要怀疑是自己打错了,还可能是石子数太大了。
规律:石子数为奇数,mex值为a[i]+1,偶数,mex值为a[i]-1。
打表代码:
#include<bits/stdc++.h> using namespace std; #define N 25 #define M 100005 int tong[M][N],mexx[M],head[M],to[M],nex[M],tot=0,val[M],ndnum,fl[M]; void add(int a,int b) { to[++tot]=b; nex[tot]=head[a]; head[a]=tot; } void dfs(int u) { if(val[u]==0) return ; if(fl[u]==0){ val[++ndnum]=val[u]; add(u,ndnum); fl[ndnum]=1; dfs(ndnum); } for(int i=0;i<=val[u]-1;i++){ val[++ndnum]=i; add(u,ndnum); fl[ndnum]=fl[u]; dfs(ndnum); } } void SG(int u) { if(val[u]==0) { mexx[u]=0; return ; } for(int i=head[u];i;i=nex[i]){ int v=to[i]; SG(v); tong[u][mexx[v]]=true; } for(int i=0;i<=20;i++) if(!tong[u][i]) { mexx[u]=i; return ; } } int main() { for(int i=1;i<=10;i++){ int id=++ndnum; val[id]=i; fl[id]=0; dfs(id); SG(id); printf("mex:%d %d\n",i,mexx[id]); } }
打表找到规律后的代码:
#include<bits/stdc++.h> using namespace std; #define ll long long int main() { freopen("nim.in","r",stdin); freopen("nim.out","w",stdout); int T,n,a; scanf("%d",&T); while(T--){ scanf("%d",&n); scanf("%d",&a); if(a&1) a++; else a--; ll ans=a; for(int i=2;i<=n;i++){ scanf("%d",&a); if(a&1) a++; else a--; ans^=a; } if(ans) printf("A\n"); else printf("B\n"); } } /* 2 2 1 2 2 2 2 */
原文地址:https://www.cnblogs.com/mowanying/p/11402738.html
时间: 2024-10-31 13:46:01