C. Perfect Triples(位运算+找规律)

题目

题意:

    给定一个无限大容器,每次你可以顺序往里面放入a,b,c。要求a,b,c从未出现过,且a ^ b ^ c = 0且a,b,c字典序尽可能小。有t组访问,要求输出该容器第n个元素。
     1 ≤ t ≤ 1 0 5 , 1 ≤ n ≤ 1 0 16 1≤t≤10^5,1≤n≤10^{16} 1t105,1n1016

分析:

    首先该题是位运算,位运算的题目一般都是每位独立来考虑的。这题的话是每次3个元素,所以是每2位来考虑。
    这种题目肯定是优先打表的,注意这种位运算的打表最好把二进制输出出来。然后禀持着每2位考虑的方向,我们会发现,每一个三元组,a是顺序增加的(打表的规律)。而b,c的每2位都取决于a,对于即(00,00,00),(01,10,11),(10,11,01),(11,01,10)。每两位都是这样的规律,所以我们就可以通过a的顺序性的规律找到a,然后通过a计算出b,c即可。

#include 
#include  
using namespace std;

typedef long long ll;

int f[3][4] = {0,1,2,3,0,2,3,1,0,3,1,2};

vector<int> ans2,ans3;

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int t;
	cin >> t;
	while( t-- )
	{
		ll n;
		cin >> n;
		ans2.clear(),ans3.clear();
		ll res1 = 1;
		while( res1 <= n ) res1 <<= 2;
		res1 >>= 2;
		ll rest = n - res1;
		res1 += rest / 3;
		ll temp = res1;
		while( temp )
		{
			int z = (temp & 3);
			ans2.push_back(f[1][z]);
			ans3.push_back(f[2][z]);
			temp >>= 2;
		}
		ll res2 = 0,res3 = 0;
		for (int i = ans2.size() - 1; i >= 0; i--)
		{
			res2 = res2 * 4 + ans2[i];
			res3 = res3 * 4 + ans3[i];
		}
		if( rest % 3 == 0 ) cout << res1 << '\n';
		else if( rest % 3 == 1 ) cout << res2 << '\n';
		else cout << res3 << '\n';
	}
	return 0;
}

你可能感兴趣的:(cf刷题)