有趣的nim game
刷题目前,请先了解nim game和sg函数的部分知识
hdoj1730.Northcott Game
当棋子紧贴着时先手必输,n行紧贴的棋子先手必输,原题相当于取完n行两棋子中间的部分构成n行紧贴的局面,等价于nim game
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
const int mod=1e9+7;
int n,m,k;
signed main(){
int T,x,y;
while (scanf("%d%d",&n,&m)==2){
int ans=0;
for (int i=1;i<=n;i++){
scanf("%d%d",&x,&y);
ans^=abs(x-y)-1;
}
if (ans==0)puts("BAD LUCK!");
else puts("I WIN!");
}
return 0;
}
hdoj6886.Tic-Tac-Toe-Nim
取完2个格子后,必存在a 0 b类似的行列,要使其构成1 0 1的必输局面,也就是(a-1)^(b-1)类似的nim game
例 0 2 3 为(2-1)^(3-1)^(4-1)^(6-1)^(7-1)^(8-1)^9
4 0 6
7 8 9
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[4][4];
int main(){
int T;
scanf("%d",&T);
while (T--){
for (int i=1;i<=3;i++){
for (int j=1;j<=3;j++){
scanf("%d",&a[i][j]);
}
}
int tot=0;
for (int i=1;i<=3;i++){
for (int j=1;j<=3;j++){
int ans=1;
for (int k=1;k<=3;k++){
for (int p=1;p<=3;p++){
if (k==i||p==j)continue;
int r=0;
for (int x=1;x<=3;x++){
for (int y=1;y<=3;y++){
if (x==i&&y==j)continue;
if (x==k&&y==p)continue;
if (x==k||x==i||y==p||y==j)r^=a[x][y]-1;
else r^=a[x][y];
}
}
if (r==0)ans=0;
}
}
if (ans==1)tot++;
}
}
cout<<tot<<endl;
}
return 0;
}
hdoj3032.Nim or not Nim?
Lasker’s Nim游戏
- 在一堆中随便取
- 1堆变成2堆
sg(4k)=4k-1;
sg(4k+1)=4k+1;
sg(4k+2)=4k+2;
sg(4k+3)=4k+4;
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
const int mod=1e9+7;
int n,m,k;
signed main(){
int T,x,y;
scanf("%d",&T);
while (T--){
scanf("%d",&n);
int ans=0;
for (int i=1;i<=n;i++){
scanf("%d",&x);
if (x%4==0)x--;
else if (x%4==3)x++;
ans^=x;
}
if (ans==0)puts("Bob");
else puts("Alice");
}
return 0;
}
hdoj5795.A Simple Nim
Lasker’s Nim游戏
- 在一堆中随便取
- 1堆变成3堆
sg(8k)=8k-1;
sg(8k+7)=8k+8;
其他一样
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
const int mod=1e9+7;
int n,m,k;
signed main(){
int T,x,y;
scanf("%d",&T);
while (T--){
scanf("%d",&n);
int ans=0;
for (int i=1;i<=n;i++){
scanf("%d",&x);
if (x%8==7)x++;
else if (x%8==0)x--;
ans^=x;
}
if (ans==0)puts("Second player wins.");
else puts("First player wins.");
}
return 0;
}
hdoj1536.S-Nim
sg函数
再一堆中取给定数组个数的数
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e4+10;
const int mod=1e9+7;
int n,m,k;
int s[N],sg[N],ha[N];
void get_sg(int n){
sg[0]=0;
int flag=1;//时间戳
memset(ha,0,sizeof ha);
for (int i=1;i<=n;i++){
for(int j=1;s[j]<=i&&j<=k;j++)
ha[sg[i-s[j]]]=flag;
for(int j=0;j<=n;j++){
if(ha[j]!=flag){
sg[i]=j;break;
}
}
flag++;
}
}
signed main(){
int T,x,y;
while (scanf("%d",&k)==1&&k){
for (int i=1;i<=k;i++)scanf("%d",&s[i]);
sort(s+1,s+1+k);
get_sg(10000);
string ss="";
scanf("%d",&m);
while(m--){
scanf("%d",&n);
int ans=0;
for (int i=1;i<=n;i++){
scanf("%d",&x);ans^=sg[x];
}
if (ans==0)ss+="L";
else ss+="W";
}
cout<<ss<<endl;
}
return 0;
}
hdoj5011.Game
- 取一堆的任意个
- 取一堆的任意个,之后把该堆分成2堆
如果之前异或和为0,在2操作后异或和必然不为0,所以还是nimgame
推广:1.分成任意堆仍是nimgame
2.只有2操作
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
const int mod=1e9+7;
int n,m,k;
signed main(){
int T,x,y;
while (scanf("%d",&n)!=EOF){
int ans=0;
for (int i=1;i<=n;i++){
scanf("%d",&x);
ans^=x;
}
if (ans==0)puts("Lose");
else puts("Win");
}
return 0;
}
hdoj1404.Digital Deletions
看起来像nim的博,此处的sg只是必胜必败局面的转换
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+10;
int n,m,k;
int sg[N];
char s[N];
int change(char *s){
int len=strlen(s),ans=0;
for (int i=0;i<len;i++){
ans=ans*10+s[i]-'0';
}
return ans;
}
void get_sg(){
sg[0]=1;
for (int i=1;i<=999999;i++){
for (int j=1;j<=i;j*=10){
int t=i/j%10;
for (int k=1;k<=t;k++){
if (j*10>i&&k==t)sg[i]|=0;
else sg[i]|=!sg[i-j*k];
}
if (t==0)sg[i]|=!sg[i/j/10];
if (j>i)break;
}
}
}
signed main(){
int T,x,y;
get_sg();
while (scanf("%s",s)!=EOF){
if (s[0]=='0')puts("Yes");
else if (sg[change(s)])puts("Yes");
else puts("No");
}
return 0;
}
hdoj5996.dingyeye loves stone
nimgame进阶 阶梯博弈
深度为奇数的进行异或和
因为当移动深度为偶数,可以将同样部分往前移动
当移动深度为奇数,可以同nimgame那样往前移动
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int n,m,k;
vector<int>v[N];
int dep[N];
void dfs(int x,int fa){
dep[x]=dep[fa]+1;
for (int i:v[x]){
if (i==fa)continue;
dfs(i,x);
}
}
signed main(){
int T,x,y;
scanf("%d",&T);
while (T--){
scanf("%d",&n);
for (int i=2;i<=n;i++){
scanf("%d",&x);x++;
v[i].push_back(x);v[x].push_back(i);
}
dep[0]=-1;
dfs(1,0);
int ans=0;
for (int i=1;i<=n;i++){
scanf("%d",&x);
if (dep[i]&1)ans^=x;
}
if (ans==0)puts("lose");
else puts("win");
for (int i=1;i<=n;i++)v[i].clear();
}
return 0;
}
hdoj3389.Game
阶梯博弈
(A+B)%30,(A+B)%21 <=> (A+B)%63

如图,图中的0-5代表%60-5,连线的代表可以互相到达,最终点必定为1,3,4,因为0不能到达
而0,2,5必定是奇数步,形成了阶梯博弈
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e3+10;
int n,m,k;
int a[N];
signed main(){
int T,x,y;
scanf("%d",&T);
for (int cas=1;cas<=T;cas++){
scanf("%d",&n);
int ans=0;
for (int i=1;i<=n;i++){
scanf("%d",&x);
if (i%6==0||i%6==2||i%6==5)ans^=x;
}
if (ans)printf("Case %d: Alice\n",cas);
else printf("Case %d: Bob\n",cas);
}
return 0;
}
hdoj4315.Climbing the Hill
阶梯博弈
把间距看成球的个数,往前走就是把球往后移动
如果k=n就和阶梯博弈一摸一样,但这里k不一定为n
特殊情况:
1.k=1,先手必赢
2.n&11且k2,a[1]--,因为a[1]不能到达山顶
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e3+10;
int n,m,k;
int a[N];
signed main(){
int T,x,y;
while (scanf("%d%d",&n,&k)!=EOF){
for (int i=1;i<=n;i++)scanf("%d",&a[i]);
if (k==1)puts("Alice");
else{
int ans=0;
if (n&1){
if(k==2)a[1]--;
ans^=a[1];
for(int i=3;i<=n;i+=2)ans^=(a[i]-a[i-1]-1);
}
else{
for(int i=2;i<=n;i+=2)ans^=(a[i]-a[i-1]-1);
}
if(ans)puts("Alice");
else puts("Bob");
}
}
return 0;
}
禁止类似码农教程的网站爬取,抄袭博客内容。
https://www.cnblogs.com/rair/

浙公网安备 33010602011771号