吐槽:赛后10min就写出来了。。。一开始把打表程序写错了导致规律找错了。。。
解法
首先打表找规律,发现和4的倍数有关,然后分n%3的值讨论。
n
m
o
d
3
=
=
1
n ~~mod~~3==1
n mod 3==1:每4的k次方分一段。每一段里的数都是连续的
n
m
o
d
3
=
=
2
n~~mod~~3==2
n mod 3==2 :分组方案是一样的,然后观察一下可以发现每个组内的数可以分成4组,有相应的规律
n
m
o
d
3
=
=
0
n~~mod~~3==0
n mod 3==0:和上一个很像,但是规律不一样。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=1e16;
inline int read(){
char c=getchar();int t=0,f=1;
while((!isdigit(c))&&(c!=EOF)){if(c=='-')f=-1;c=getchar();}
while((isdigit(c))&&(c!=EOF)){t=(t<<3)+(t<<1)+(c^48);c=getchar();}
return t*f;
}
int t,n,pre[60],mx;
const int step2[4]={0,2,3,1};
const int step3[4]={0,3,1,2};
signed main(){
//freopen("3.in","r",stdin);
//freopen("g.out","w",stdout);
t=read();
pre[0]=1;
for(int i=1;i<=59;i++){
pre[i]=pre[i-1]*4;
if(pre[i]>maxn){mx=i;
break;}
}
while(t--){
n=read();
if(n<=3){
printf("%d\n",n);
continue;
}
int m=(n+2)/3;
int sum=0,pos=0;
for(int i=0;i<mx;i++){
sum=sum+pre[i];
if(sum>=m){
pos=i;break;
}
}
sum=sum-pre[pos]+1;
int fr=pre[pos]+(m-sum);
int len=fr-pre[pos];
if(n%3==1){printf("%lld\n",fr);}
else if(n%3==2){
int gen=pre[pos]*2;
for(int i=pos;i>0;i--){
gen=gen+step2[(len/pre[i-1])%4]*pre[i-1];
}
printf("%lld\n",gen);
}
else {
int gen=pre[pos]*3;
for(int i=pos;i>0;i--){
gen=gen+step3[(len/pre[i-1])%4]*pre[i-1];
}
printf("%lld\n",gen);
}
}
return 0;
}