翻硬币游戏
$N$枚硬币排成一排,有的正面朝上,有的反面朝上。我们从左开始对硬币按1 到N编号。
最右边那个硬币的必须是从正面翻到反面,.谁不能翻谁输。
局面的SG值为局面中每个正面朝上的棋子单一存在时的SG值的异或和
1.每次只能翻一个硬币,
显然,每个硬币的SG值为1
2.每次能翻转一个或两个(不用连续)
每个硬币的SG值为其从左到右的编号位置,从0开始
#include <bits/stdc++.h> #define ll long long #define rep(ii,a,b) for(int ii=a;ii<=b;++ii) #define per(ii,a,b) for(int ii=b;ii>=a;--ii) #define show(x) cout<<#x<<"="<<x<<endl #define show2(x,y) cout<<#x<<"="<<x<<" "<<#y<<"="<<y<<endl #define show3(x,y,z) cout<<#x<<"="<<x<<" "<<#y<<"="<<y<<" "<<#z<<"="<<z<<endl #define show4(w,x,y,z) cout<<#w<<"="<<w<<" "<<#x<<"="<<x<<" "<<#y<<"="<<y<<" "<<#z<<"="<<z<<endl #define show5(v,w,x,y,z) cout<<#v<<"="<<v<<" "<<#w<<"="<<w<<" "<<#x<<"="<<x<<" "<<#y<<"="<<y<<" "<<#z<<"="<<z<<endl #define showa(x,a,b) cout<<#x<<": ";rep(i,a,b) cout<<x[i]<<' ';cout<<endl using namespace std;//head const int maxn=1e5+10,maxm=2e6+10; int casn,n,m,k,kase; int sg[maxn]; int getmex(bool vis[]){ int mex=0; while(vis[mex]) ++mex; return mex; } int getsg(int now){ if(~sg[now]) return sg[now]; bool vis[now+1]={0}; rep(i,1,now-1) vis[getsg(i)]=1; vis[now]=1; return sg[now]=getmex(vis); } int main(){IO; memset(sg,-1,sizeof sg); cin>>n; getsg(n); showa(sg,1,n); }
3.每次只能翻转连续k枚硬币
每个硬币的SG值为0000...100000..1,其中每k个为一个周期,每个周期前k-1个为0
#include <bits/stdc++.h> #define rep(ii,a,b) for(int ii=a;ii<=b;++ii) #define per(ii,a,b) for(int ii=b;ii>=a;--ii) #define show(x) cout<<#x<<"="<<x<<endl #define show2(x,y) cout<<#x<<"="<<x<<" "<<#y<<"="<<y<<endl #define show3(x,y,z) cout<<#x<<"="<<x<<" "<<#y<<"="<<y<<" "<<#z<<"="<<z<<endl #define show4(w,x,y,z) cout<<#w<<"="<<w<<" "<<#x<<"="<<x<<" "<<#y<<"="<<y<<" "<<#z<<"="<<z<<endl #define show5(v,w,x,y,z) cout<<#v<<"="<<v<<" "<<#w<<"="<<w<<" "<<#x<<"="<<x<<" "<<#y<<"="<<y<<" "<<#z<<"="<<z<<endl #define showa(x,a,b) cout<<#x<<": ";rep(i,a,b) cout<<x[i]<<' ';cout<<endl using namespace std;//head const int maxn=1e5+10,maxm=2e6+10; int casn,n,m,k,kase; int sg[maxn]; int getmex(bool vis[]){ int mex=0; while(vis[mex]) ++mex; return mex; } int getsg(int now,int k){ if(~sg[now]) return sg[now]; bool vis[now+1]={0}; int flag=0; rep(i,now-k+1,now-1){ flag^=getsg(i,k); } vis[flag]=1; return sg[now]=getmex(vis); } int main(){IO; memset(sg,-1,sizeof sg); cin>>n>>k; rep(i,0,k-1) sg[i]=0; getsg(n,k); showa(sg,1,n); }
4:每次翻动第X个硬币后,必须翻动其左侧最近K个硬币中的一个,除非X是小于等于3的
SG值为1,2,3,4..K,0,1,2,3,4..K,0每K+1个数字为一个周期
#include <bits/stdc++.h> #define rep(ii,a,b) for(int ii=a;ii<=b;++ii) #define per(ii,a,b) for(int ii=b;ii>=a;--ii) #define show(x) cout<<#x<<"="<<x<<endl #define show2(x,y) cout<<#x<<"="<<x<<" "<<#y<<"="<<y<<endl #define show3(x,y,z) cout<<#x<<"="<<x<<" "<<#y<<"="<<y<<" "<<#z<<"="<<z<<endl #define show4(w,x,y,z) cout<<#w<<"="<<w<<" "<<#x<<"="<<x<<" "<<#y<<"="<<y<<" "<<#z<<"="<<z<<endl #define show5(v,w,x,y,z) cout<<#v<<"="<<v<<" "<<#w<<"="<<w<<" "<<#x<<"="<<x<<" "<<#y<<"="<<y<<" "<<#z<<"="<<z<<endl #define showa(x,a,b) cout<<#x<<": ";rep(i,a,b) cout<<x[i]<<' ';cout<<endl using namespace std;//head const int maxn=1e5+10,maxm=2e6+10; int casn,n,m,k,kase; int sg[maxn]; int getmex(bool vis[]){ int mex=0; while(vis[mex]) ++mex; return mex; } int getsg(int now,int k){ if(~sg[now]) return sg[now]; bool vis[now+1]={0}; rep(i,max(0,now-k),now-1){ vis[getsg(i,k)]=1; } return sg[now]=getmex(vis); } int main(){ memset(sg,-1,sizeof sg); cin>>n>>k; getsg(n,k); showa(sg,1,n); }
5.每次可以翻额外的0,1,2,3..k个硬币