【题解】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;
}

浙公网安备 33010602011771号