【题解】P6819 [PA 2012 Finals] Binary Dodgeball

思路

找规律。

首先,容易发现这个游戏其实就是基本的硬币游戏。

所以对于如果有 \(k\) 个数,它的 SG 函数为 \(\displaystyle\bigoplus_{i=1}^n \log_2 \text{lowbit}(i)\)

我们直接对其进行打表找规律,打表代码:

const int MAXN = 30010;
int n,MAXQ,f[MAXN];
bitset<MAXN> vis;
int get(int x,int y){
  int tot = 0;
  while(!(x%y)){
    tot++;
    x/=y;
  }
  return tot;
}
int y = 0;
bitset<64> u;
int tot = 0;
signed main(){
  int ans = 0;
  for(int i = 1;i<=65000000000ll;i++){
    ans ^= (int)log2(i&-i);
    if(ans==0){
      cout << ++tot << " " << i << endl;
    }
  }
  return 0;
}

输出出来的结果为:

1 1
2 10
3 11
4 34
5 35
6 40
7 41
8 68
9 69
10 78
11 79
12 102
13 103
14 108
15 109
16 130
......

容易发现,对于一个第 \(k\) 个可行的数,其答案应该为第其所有二进制位个数异或起来的结果。定义 \(kth(i)\) 表示第 \(i\) 个可行的数。例如:\(kth(11)=kth(1)\oplus kth(2)\oplus kth(8)=1\oplus 10\oplus 68=79\)

所以我们可以将上面的程序稍加修改求出前 \(30\) 个二的幂次数最后异或起来即可。(对于上面的程序,跑大约 \(11\) 多分钟就能跑出来)

上面的程序:

const int MAXN = 30010;
int n,MAXQ,f[MAXN];
bitset<MAXN> vis;
int get(int x,int y){
  int tot = 0;
  while(!(x%y)){
    tot++;
    x/=y;
  }
  return tot;
}
int y = 0;
bitset<64> u;
int tot = 0;
signed main(){
//		read(n);
  int ans = 0;
  for(int i = 1;i<=65000000000ll;i++){
    ans ^= (int)log2(i&-i);
    if(ans==0){
      tot++;
      if((tot&-tot)==tot) cout << tot << " " << i << endl;
    }
  }
  return 0;
}

输出为:

1 1
2 10
4 34
8 68
16 130
32 514
64 1028
128 2050
256 4112
512 8194
1024 16388
2048 32770
4096 131074
8192 262148
......(我就不放完了,代码中见)

代码

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
namespace gtx{
//	Fast IO
	void read(int &x){
		x = 0;int h = 1;char tmp;
		do{tmp=getchar();if(tmp=='-')h*=-1;}while(!isdigit(tmp));
		while(isdigit(tmp)) x*=10,x+=tmp-'0',tmp=getchar();
		x*=h;
	}
	void read(char &x){do{x=getchar();}while(x==' '||x=='\n'||x=='\r');}
	void write(char x){putchar(x);}
	void write(int x){
		if(x<0) putchar('-'),x=-x;int st[200]={0},tot=0;
		do st[++tot]=x%10,x/=10; while(x);
		while(tot){putchar(st[tot--]+'0');}
	}
	void write(int x,char y){write(x);write(y);}
#ifndef int
	void read(long long &x){
		x = 0;int h = 1;char tmp;
		do{tmp=getchar();if(tmp=='-')h*=-1;}while(!isdigit(tmp));
		while(isdigit(tmp)) x*=10,x+=tmp-'0',tmp=getchar();
		x*=h;
	}
	void write(long long x){
		if(x<0) putchar('-'),x=-x;int st[200]={0},tot=0;
		do st[++tot]=x%10,x/=10; while(x);
		while(tot){putchar(st[tot--]+'0');}
	}
	void write(long long x,char y){write(x);write(y);}
#endif
	int y[60] = {1,10,34,68,130,514,1028,2050,4112,8194,16388
,32770,131074,262148,524290,1048592,2097154, 4194308
,8388610,16777472,33554434,67108868,134217730,268435472,536870914
,1073741828,2147483650,8589934594,17179869188,34359738370
};
	signed main(){
		int k;
		cin >> k;
		int u = 0;
		int ans = 0;
		while(k){
			if(k&1){
				ans^=y[u];
			}
			u++;
			k>>=1;
		}
		write(ans);
		return 0;
	}
}
signed main(){
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
//	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	int T = 1;
//	gtx::read(T);
	while(T--) gtx::main();
	return 0;
}
posted @ 2025-01-25 21:41  GuTongXing  阅读(45)  评论(0)    收藏  举报