E.パーフェクトトリプル
トピックの要約:
無限配列\(s \)があります。(空から開始)
辞書順で3つの最小数を見つけるたびに、\((a、b、c)\)は次の条件を満たす。
- \(a \ oplus b \ oplus c = 0 \)。
- \(a、b、c \ notin s \)。
\(t \)回、毎回配列内の項目数を尋ねます\(n \)。
アイデア:
テーブルをプレイした後、トリプルの最初の項目は常に\(4 ^ x \)の後に連続する番号であることがわかりました。このようにして、2ビットの下で2ビットを転送しようとします
(つまり、4進数で、XORを便利に見せるために、このように説明します)。
各2ビットが取ることができる値は\(00、01、10、11 \)です。。
最初に、\(1 \から4 ^ n-1 \)の数が使い果たされたと想定します。次に、\(4 ^ n \から4 ^ {n + 1} -1 \)を考えます。\(a <b <c \)
を取得するには、最上位の2 桁は\(01、10、11 \)のみにする必要があります。つまり、\(a、b、c \)の最上位の2 桁は互いに異なります。最初の2つがわかったので、続けて見下ろします。最初に、サンプルで指定された項目(バイナリ)を次の表の形式で示します。
\(a \) | \(b \) | \(a \ oplus b \) |
---|---|---|
\(00 \) | \(00 \) | \(00 \) |
\(01 \) | \(10 \) | \(11 \) |
\(10 \) | \(11 \) | \(01 \) |
\(11 \) | \(01 \) | \(10 \) |
4進数で(2桁単位)、すべての値が上記の条件を満たしていると大胆に推測します。
- 2桁の場合、\((a、b、c)\)には\(1,2,3 \)しかなく、これは明らかに満足されます。
- \(a、b、c \)が\(2k \)ビットで満たされていると仮定して、\(2k + 2 \)ビットを確認します。
まず、この\(2k \)ビットを左に2つシフトします(いずれかを設定します)値のペアは\(pa、pb、pc \)、明らかに\(pa \ oplus pb = pc \))です。最小の辞書式順序の場合、最初に\(a \):
\(00 \):を検討します\(pa + 00、pb + 00、pc + 00 \)が確立されました。
\(01 \):\(b \)の場合、\(00、01 \)は真ではありません(\(b、c \)が繰り返されます)、それから\(pa + 01、pb + 10、pc + 11 \)。
...
残りのハンドでは、上の表が実際に満足していることがわかります。
長い我々はれるように決意として(N- \)\数が属するトリプル\((A、B、C )\) \(A \) 、この値を決定します。
コード:
#include "iostream"
#include "stdio.h"
#include "string.h"
#include "algorithm"
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
const int N=1e6+5;
const ll mod=998244353;
const double eps=1e-5;
//const double pi=acos(-1);
#define ls p<<1
#define rs p<<1|1
ll f[3][4]={{0,3,1,2},{},{0,2,3,1}};
void solve(ll x,int y)
{
if(y==1)
{
printf("%lld\n",x);
return;
}
ll ans=0,p=1;
while(x)
{
ans=ans+f[y][x%4]*p;
x>>=2;
p<<=2;
}
printf("%lld\n",ans);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
int _;
ll n;
cin>>_;
while(_--)
{
cin>>n;
ll j=1,a;
while(j<=n) j<<=2;
j>>=2;
if(j+2>=n) a=j;
else a=j+(n-j)/3;
solve(a,n%3);
}
return 0;
}