联合省选2024 D1T2

posted on 2024-03-06 11:40:42 | under | source

\(\rm trie\) 后二分答案。

遍历 \(\rm trie\),考虑在此过程中逐位确定 \(x\),显然某一位 \(x=0\) 不会对 \(\rm trie\) 这层的结构产生影响,\(x=1\) 时则更换 \(0,1\) 子树。

然后对 \(k\) 某一位取值和 \(\rm trie\) 树上对应位边权进行分讨:

  1. \(k=0\):此时 \(1\) 子树不用讨论跳过,进入 \(0\) 子树遍历。
  2. \(k=1\):此时 \(0\) 子树必须全部定向加强,进入 \(1\) 子树遍历。

然后 \(x\) 这一位的取值也要进行讨论,无非更换顺序而已,没有什么本质区别。

于是我们 \(\rm dfs\) 过程中额外记录定向加强的最小元素、定向加强的 \(b\) 之和、\(x\) 的值用于计算答案即可。

分析复杂度:根据上述讨论,每个点只会被遍历一次,复杂度 \(O(nk^2)\),可以拿到 \(72\) 分~

正解:考虑直接在遍历过程中逐位确定 \(k\),因为是由高到低所以是正确的。

那么这样优在哪呢?不难发现如果 \(k\) 的某一位可以取 \(1\) 就没必要遍历 \(0\) 了,所以复杂度其实是 \(O(nk)\) 的。

考虑判断是否有合法解即可,显然 \(k=0\) 必有合法解。\(k=1\) 时对异或后为 \(0\) 的子树判断极端情况即可。

代码

#include<bits/stdc++.h>
using namespace std;

#define int long long
#define intt __int128
const int N = 2e5 + 5, K = 125;
const intt qwq = 1, inf = qwq << 120;
int c, T, n, m, k, b[N], B;
int ch[N * K][2], bs[N * K], tot;
intt mi[N * K], bt[K], btt[K], a[N], A, ans;

void read(__int128 &x){
	char c; bool f = 0;
	while(((c = getchar()) < '0' || c > '9') && c != '-');
	if(c == '-') {f = 1; c = getchar();}
	x = c - '0';
	while((c = getchar()) >= '0' && c <= '9') x = x * 10 + c - '0';
	if(f) x = -x;
}
void write(__int128 x){
	if(x < 0) {putchar('-'); x = -x;}
	if(x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
inline void clen(int u) {ch[u][0] = ch[u][1] = 0, mi[u] = inf, bs[u] = 0;} //初始化trie上一节点 
inline void dfs(int u, intt _xor, intt ami, int bsum, int layer, intt _check){ //trie遍历的点、x已确定的部分、定向加强的最小元素、定向加强的花费和、trie上遍历的层级、答案值 
//	write(_xor);
	if(layer == -1){ //最小值可能落在定向加强元素或所有元素里
		ans = max(ans, _check); 
		return ; 
	} 
	if(!u) {ans = max(ans, ami + _xor + bt[layer + 1] - 1); return ;} //注意有坑:判断完是否遍历结束后再判断空节点
	
	bool flag = 0; //最重要的一点:layer=1不行了才去试layer=0
	//剪枝:在执行前先判断是否存在合法解,保证每次遍历都得到至少一个解 
	//layer=1
	if(min(ami, mi[ch[u][0]]) + _xor + bt[layer] - 1 >= _check + bt[layer] && bsum + bs[ch[u][0]] <= m) 
		dfs(ch[u][1], _xor, min(ami, mi[ch[u][0]]), bsum + bs[ch[u][0]], layer - 1, _check ^ bt[layer]), flag = true; 
	if(min(ami, mi[ch[u][1]]) + _xor + bt[layer + 1] - 1 >= _check + bt[layer] && bsum + bs[ch[u][1]] <= m)
		dfs(ch[u][0], _xor ^ bt[layer], min(ami, mi[ch[u][1]]), bsum + bs[ch[u][1]], layer - 1, _check ^ bt[layer]), flag = true;
	//layer=0 
	if(flag) return ;
	dfs(ch[u][0], _xor, ami, bsum, layer - 1, _check);
	dfs(ch[u][1], _xor ^ bt[layer], ami, bsum, layer - 1, _check);
}	
signed main(){
//	freopen("P10218_7.in", "r", stdin);
	bt[0] = qwq; 
	for(int i = 1; i < K; ++i) bt[i] = bt[i - 1] * 2;
	cin >> c >> T;
	while(T--){
		scanf("%lld%lld%lld", &n, &m, &k);
		mi[0] = inf, clen(tot = 1), B = 0, A = bt[120];
		for(int i = 1; i <= n; ++i) read(a[i]), A = min(A, a[i]);
		for(int i = 1; i <= n; ++i) scanf("%lld", &b[i]), B += b[i];
		if(B <= m) {write(A + bt[k] - 1), putchar('\n'); continue;}
		for(int i = 1; i <= n; ++i){
			bs[1] += b[i], mi[1] = min(mi[1], a[i]);
			for(int j = k - 1, u = 1, c; ~j; --j){
				c = (a[i] >> j) & 1;
				if(!ch[u][c]) clen(ch[u][c] = ++tot);
				u = ch[u][c];
				bs[u] += b[i], mi[u] = min(mi[u], a[i]);
			}
		}
		ans = 0;
		dfs(1, 0, inf, 0, k - 1, 0);
		write(ans), putchar('\n');
	}
	return 0;
}
posted @ 2026-01-14 18:08  Zwi  阅读(0)  评论(0)    收藏  举报