CF1338C Perfect Triples

CF1338C Perfect Triples

通过打表可以发现,\(a\) 的分布是一段一段的,且符合 \([2^{2 \times k}, 2 ^ {2 \times k + 1})\),其中 \(k\) 取任意自然数(每一段不妨记为第 \(k\) 大组)。显然可以通过二分或等比数列求和的方式解出询问的 \(n\) 具体属于哪个三元组,以及第几个大组。

然后是 \(b\)\(c\),显然求出 \(b\) 就求出 \(c\) 了,而且也比较好转化。具体怎么求 \(b\) 呢,通过观察发现在二进制下从最低的两位开始,每两位的变化都是 \(00, 10, 11, 01\),高位变化则低位重新开始变化。那么就可以从高到低一位一位把 \(b\) 给剥离出来了。特判的地方代码注释有标注。

#include<bits/stdc++.h>
#define F(i,l,r) for(int i(l); i <= (r); ++ i)
#define G(i,r,l) for(int i(r); i >= (l); -- i)
#define int ll
using namespace std;
using ll = long long;
const int N = 2e5;
int n, T, a1, a2, a3;
int qp(int w){
	int ret = 1ll << (2 * w);
	return ret;
}
int sol(int k, int i){ // 求第 k 大组第 i 小组的b;
	if(k == 1 && i == 1) return 2;
	int s = 2;
	G(h, k - 1, 1){
		int viv = qp(h - 1);
		if(viv * 1ll >= i){
			s = (s << 2);
		} 
		else if(viv * 2ll >= i){
			s = ((s << 2) | 2), i -= viv;
		}
		else if(viv * 3ll >= i){
			s = ((s << 2) | 3), i -= viv * 2ll;
		}
		else{
			s = ((s << 2) | 1), i -= viv * 3ll;
		}
	}
	return s;
}
signed main(){
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	cin >> T;
	while(T --){
		cin >> n; // n groups
		int m = n / 3; // 第几个三元组
		int sm = 1, k = 0, maxn = m * 3 + 1;
		while(sm <= maxn) ++ k, sm *= 4ll;
		-- k;  
		int pp = 2 * k;
		int u = (1ll << pp);
		int r = n - (u - 1); // 本大组的第几个数 
		a1 = u + r / 3;
		if(r % 3 == 0){
			if(r == 0){ // 本大组的最后一个c 
				a1 = u / 2ll - 1;
				int a2 = sol(k, u / 4ll), a3 = a1 ^ a2;
				cout << a3 << '\n';
			} 
			else{
				int a2 = sol(k + 1, r / 3), a3 = (a1 - 1) ^ a2;
				cout << a3 << '\n';
			}
		}
		else if(r % 3 == 1){
			cout << a1 << '\n'; 
		}
		else{
			cout << sol(k + 1, r / 3 + 1) << '\n';
		}
	}
	return fflush(0), 0;
}
posted @ 2025-07-28 16:36  superl61  阅读(6)  评论(0)    收藏  举报