题解:qoj7411 Bitwise Xor

题意:给出一个序列 \(a\) 和一个数 \(x\),要求有多少个子序列下标为 \(b_1,b_2\cdots b_k\),满足 \(\forall i < j,a_{b_i}\oplus a_{b_j} \ge x\)

做法:

这个每个都要求限制非常麻烦,我们考虑优化这个限制,去除掉一些没用的。

一个观察是,如果我们有一个序列 \(x_1,x_2\cdots x_n\),那么我们将其排序后,最小值一定会在 \(i,i+1\) 处取到,接下来我们给出证明。

假设我们有三个位置 \(i<j<k\),第一个从高位到低位他们不同的位置只可能是 \(0,1,1\) 或者 \(0,0,1\),那么很显然我们取 \((i,j),(j,k)\) 一定有一个优于 \((i,k)\)

那么我们就可以直接将 \(a\) 排序,记 \(dp_i\) 是以 \(i\) 结尾的子序列个数,那么我们可以直接在 Trie 树上修改统计。

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 3e5 + 5, N = 2e6, mod = 998244353;
int n, x, a[maxn];
struct Trie {
	int son[maxn * 60][2], tot = 1, sz[maxn * 60];
	void insert(int x, int val) {
		int p = 1;
		for (int i = 59; i >= 0; i--) {
			int id = ((x >> i) & 1);
			if(!son[p][id])
				son[p][id] = ++tot;
			p = son[p][id], sz[p] += val, sz[p] %= mod;
		}
	}
	int query(int x, int lim) {
		int p = 1, ans = 0;
		for (int i = 59; i >= 0; i--) {
			int xt = ((x >> i) & 1);
			if(((lim >> i) & 1))
				p = son[p][1 - xt];
			else
				ans = (ans + sz[son[p][1 - xt]]) % mod, p = son[p][xt];
		//	cout << i << " " << ans << " " << p << " " << ((lim >> i) & 1) << " " << lim << endl;
		}
		ans += sz[p]; ans %= mod;
		return ans;
	}
} tree;
int ans = 0, dp[maxn];
signed main() {
	cin >> n >> x;
	for (int i = 1; i <= n; i++)
		cin >> a[i];
	sort(a + 1, a + n + 1);
	for (int i = 1; i <= n; i++) {
		dp[i] = tree.query(a[i], x) + 1;
		tree.insert(a[i], dp[i]);
		ans = (ans + dp[i]) % mod;
	//	cout << a[i] << " " << dp[i] << endl;
	}
	cout << ans << endl;
	return 0;
}
/*
3 0
0 1 2
*/
posted @ 2025-07-22 22:39  LUlululu1616  阅读(35)  评论(0)    收藏  举报