題目鏈接:點擊查看
題目大意:序列 s 是一個無限數列,現在給出構造方法:
- 選擇三個數 a b c ,將其依次加到序列 s 的最後面,三個數需要滿足:
- a b c 在序列 s 中均未出現過
- a b c 是字典序最小的數列
- a ^ b ^ c = 0
現在給出一個 n ( <= 1e16 ) ,求出數列的第 n 項
題目分析:乍一看可能沒什麼思路,不過看起來可以打表,於是打表觀察一下,打表代碼放在最後
打出表後可以發現,以 a b c 爲整體的數對被分成了好幾大段,每一段的長度分別爲 1,4,16,64....4^n,其中在每一大段中,a 都是依次增大的,這是一個比較明顯的規律
因爲這是對於異或的操作,所以將所有數都轉換爲二進制再看一看,會發現 b 和 a 有着某種微妙的關係,仔細觀察觀察或者大膽猜想一下,可以知道這個與四進制有關
將所有數轉換爲四進制後,就能看出 a 與 b 其中的相同位上:
- a == 0 時 b =0
- a == 1 時 b = 2
- a == 2 時 b = 3
- a == 3 時 b = 1
這樣就能在知道 n 的基礎上,求出第 n 個數的行與列的座標,然後求出 a 和 b ,根據 a^b^c=0,得到 c=a^b,這樣就能求出答案了
代碼:
AC代碼:
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<unordered_map>
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const int N=1e5+100;
const int b[]={0,2,3,1};
LL get_num1(LL x)
{
LL base=1;
while(base<x)
{
x-=base;
base<<=2;
}
return base+x-1;
}
LL get_num2(LL x)
{
LL num1=get_num1(x);
LL ans=0;
for(int i=0;i<=60;i+=2)
ans+=(1LL<<i)*b[(num1>>i)%4];
return ans;
}
int main()
{
#ifndef ONLINE_JUDGE
// freopen("input.txt","r",stdin);
// freopen("output.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);
int w;
cin>>w;
while(w--)
{
LL n;
scanf("%lld",&n);
LL row=(n-1)/3+1;
int col=(n-1)%3;
LL num1=get_num1(row);
LL num2=get_num2(row);
LL num3=num1^num2;
if(col==0)
printf("%lld\n",num1);
else if(col==1)
printf("%lld\n",num2);
else
printf("%lld\n",num3);
}
return 0;
}
打表代碼:
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<unordered_map>
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const int N=1e5+100;
bool vis[N];
void print(int num)//輸出四進制
{
string ans;
for(int i=1;i<=5;i++)
{
ans+=to_string(num%4);
num/=4;
}
reverse(ans.begin(),ans.end());
cout<<ans<<' ';
}
int main()
{
#ifndef ONLINE_JUDGE
// freopen("input.txt","r",stdin);
// freopen("output.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);
for(int k=1;k<=100;k++)
{
for(int i=1;i<=1000;i++)
{
if(!vis[i])
{
for(int j=i+1;j<=1000;j++)
{
if(!vis[j]&&!vis[i^j])
{
vis[i]=vis[j]=vis[i^j]=true;
printf("%d %d %d ",i,j,i^j);
print(i),print(j),print(i^j);
puts("");
goto end;
}
}
}
}
end:;
}
return 0;
}