嘘~ 正在从服务器偷取页面 . . .

CF1338C Perfect Triples 题解


CF1338C Perfect Triples 题解

题目链接:Perfect Triples

题意

通过如下方式构造一个无穷数列 \(S\)
1. 选择一个字典序最小的有序三元组 \((a,b,c)\) ,且满足 \(a,b,c \notin S~, a \oplus b\oplus c=0\)。 2. 将 \(a,b,c\) 依次加入数列 \(S\)

\(T(T \le 10^5)\) 组询问,每次给出一个数 \(n(1\le n\le 10^{16})\) ,求数列 \(S\) 的第 \(n\) 项。

打表找规律题,打表程序:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)())

struct node { int a, b, c; };
bool operator<(node x, node y)
{
	if(x.a != y.a) return x.a < y.a;
	else if(x.b != y.b) return x.b < y.b;
	return x.c < y.c;
}
vector<node> vec; char used[1111];
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	// freopen("check.in","r",stdin);
	freopen("check.out","w",stdout);
	for(int i = 1; i <= 1000; i++)
		for(int j = i + 1; j <= 1000; j++)
			for(int k = j + 1; k <= 1000; k++)
				if((i ^ j ^ k) == 0 && !used[i] && !used[j] && !used[k])
					vec.push_back({i, j, k}), used[i] = used[j] = used[k] = 1;
	sort(vec.begin(), vec.end());
	for(auto i : vec) cout << i.a << ' ' << i.b << ' ' << i.c << '\n';
	return 0;
}

表(部分):

1 2 3
4 8 12
5 10 15
6 11 13
7 9 14
16 32 48
17 34 51
18 35 49
19 33 50
20 40 60
21 42 63
22 43 61
23 41 62
24 44 52
25 46 55
26 47 53
27 45 54
28 36 56
29 38 59
30 39 57
31 37 58
64 128 192
65 130 195

可以发现,答案被分成了若干块,每一块的 \(a\) 都是 \(2^k\)\(2^{k+1}-1\)​ 的连续整数

\(b\) 的规律有一点不太容易看得出来,我们可以这么看

16 32 48 // 0
17 34 51 // 2
18 35 49 // 3   // 0
19 33 50 // 1

20 40 60
21 42 63
22 43 61        // 2
23 41 62

24 44 52
25 46 55
26 47 53        // 3
27 45 54

28 36 56
29 38 59
30 39 57        // 1
31 37 58

于是我们可以通过递归构造 \(b\) ,而 \(c=a\oplus b\) 可以很容易得到。实现的细节比较繁琐。

时间复杂度 \(\mathcal{O}(T\log n)\)

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)())

int calc(int x, int y)
{
    if(x == 1) return 1;
    int t = x / 4;
    if(y <= t) return calc(t, y);
    else if(y <= 2 * t) return calc(t, y - t) + 2 * t;
    else if(y <= 3 * t) return calc(t, y - 2 * t) + 3 * t;
    else return calc(t, y - 3 * t) + t;
}
void solve()
{
    int n, tmp; cin >> n; tmp = n % 3;
    n = (n + 2) / 3; int pos = 0, cnt = 0;
    while(pos + (1ll << cnt) < n) { pos += (1ll << cnt); cnt += 2; }
    int res = 3 * pos;
    if(tmp == 1) cout << res + (n - pos) << '\n';
    else if(tmp == 2) cout << res + (1ll << cnt) + calc(1ll << cnt, n - pos) << '\n';
    else cout << ((res + (n - pos)) ^ (res + (1ll << cnt) + calc(1ll << cnt, n - pos))) << '\n';

}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    int qwq; cin >> qwq; while(qwq--) solve();
    return 0;
}

参考文献

是谁表都打出来了找不到规律的?

[1] https://www.luogu.com.cn/article/t7m0qhtx


文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录