联合省选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\) 树上对应位边权进行分讨:
- \(k=0\):此时 \(1\) 子树不用讨论跳过,进入 \(0\) 子树遍历。
- \(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;
}

浙公网安备 33010602011771号