首页 > 其他分享 >[luoguP10218/省选联考 2024] 魔法手杖

[luoguP10218/省选联考 2024] 魔法手杖

时间:2024-12-29 11:08:48浏览次数:3  
标签:cur idx rs 省选 luoguP10218 int ans I128 联考

题意

给定 \(a_1,a_2,\dots,a_n\) 以及 \(b_1,b_2,\dots,b_n\),满足 \(a_i \in [0,2^k-1]\) 以及 \(b_i\geq 0\),你需要给出 \(S \subseteq \{1,2,\dots,n\}\) 以及 \(x \in [0,2^k-1]\) 满足以下条件:

  • \(\sum \limits_{i\in S} b_i\leq m\);
  • 满足以上条件的前提下,最大化 \(val(S,x)=\min(\min \limits_{i \in S}(a_i+x),\min \limits_{i \in U \backslash S}(a_i \oplus x))\) 的值。

你只需要给出最大的 \(val(S,x)\) 的值即可。

sol

因为有异或操作,所以考虑 0/1Trie。由于二进制的特殊性,如果能够使高位更大的话,那么低位无论如何取都不会更优,符合贪心的思想。因此在 Trie 上遍历进行贪心。
遍历时,由于需要异或,如果该位答案取 \(1\),那么一定有一棵子树需要全部改用 \(+\) 操作(当且仅当需要更改操作的元素的 \(b\) 之和不超过 \(m\),且更改操作的元素的最小值加上可能的 \(x\) 的最大取值比当前答案的最小取值大时才可改用),否则只能取 \(0\)。因为不知道哪一棵子树需要更改操作,因此进行 dfs。
需要注意边界情况:

  1. 遍历完 \(k\) 位,此时遍历到的答案即为备选答案;
  2. Trie 树上不存在该节点,这意味着最终的答案是 \(a_i+x\),因此备选答案即为最小的更改操作元素加上可能的 \(x\) 最大取值。

INF 一定要开够

代码

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;
typedef __int128 I128;
typedef long long LL;

const int N = 100005, K = 125;
const I128 INF = 1e37;

int tr[N * K][2], idx;
I128 amin[N * K];
LL bsum[N * K];
int c, T;
int n, m, k;
int b[N];
I128 a[N];
I128 res = 0;

void read(__int128 &x){
	// read a __int128 variable
	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){
	// print a __int128 variable
	if(x < 0){putchar('-'); x = -x;}
	if(x > 9)write(x / 10);
	putchar(x % 10 + '0');
}

int create(){
    idx ++ ;
    tr[idx][0] = tr[idx][1] = 0;
    amin[idx] = INF, bsum[idx] = 0;
    return idx;
}

void insert(int x){
    I128 xc = a[x];
    int p = 1;
    for (int i = k - 1; i >= 0; i -- ){
        int c = 0;
        if (xc >= ((I128) 1 << i)) xc -= (I128) 1 << i, c = 1;
        if (!tr[p][c]) tr[p][c] = create();
        p = tr[p][c];
        // printf("@@@%d %d\n", c, p);
        amin[p] = min(amin[p], a[x]);
        bsum[p] += b[x];
    }
}

void debug(int pos, int k, I128 mina, LL sumb, I128 x, I128 ans){
    // printf("##%d %d ", pos, k);
    // write(mina);
    // printf(" %lld ", sumb);
    // write(x);
    // printf(" ");
    // write(ans);
    // puts("");
}

void dfs(int pos, int k, I128 mina, LL sumb, I128 x, I128 ans) {
    debug(pos, k, mina, sumb, x, ans);
    if (k <= -1) {
        res = max(res, ans);
        return ;
    }
    I128 cur = (I128) 1 << k, all = cur - 1;
    if (!pos) {
        res = max(res, mina + (x | cur | all));
        return ;
    }

    bool flag = false;
    int ls = tr[pos][0], rs = tr[pos][1];
    // printf("@!%d %d\n", ls, rs);
    // write(cur);
    // printf(" ");
    // write(all);
    // puts("");
    // printf("L!#!%d %d %lld ", pos, k, bsum[ls]);
    // write(min(amin[ls], mina) + (x | all));
    // putchar(' ');
    // write(ans | cur);
    // puts("");
    if (sumb + bsum[ls] <= m && min(amin[ls], mina) + (x | all) >= (ans | cur)) {
        // puts("LIF");
        flag = true;
        dfs(rs, k - 1, min(mina, amin[ls]), sumb + bsum[ls], x, ans | cur);
    }
    // printf("R!#!%d %d %lld ", pos, k, bsum[rs]);
    // write(min(amin[rs], mina) + (x | cur | all));
    // putchar(' ');
    // write(ans | cur);
    // puts("");
    if (sumb + bsum[rs] <= m && min(amin[rs], mina) + (x | cur | all) >= (ans | cur)) {
        // puts("RIF");
        flag = true;
        dfs(ls, k - 1, min(mina, amin[rs]), sumb + bsum[rs], x | cur, ans | cur);
    }
    if (flag) return ;
    dfs(ls, k - 1, mina, sumb, x, ans);
    dfs(rs, k - 1, mina, sumb, x | cur, ans);
}

int main(){
    // freopen("xor.in", "r", stdin);
    // freopen("ans.out", "w", stdout);
    scanf("%d%d", &c, &T);
    while (T -- ){
        idx = 0;
        create();
        amin[0] = INF;

        scanf("%d%d%d", &n, &m, &k);
        I128 mina = INF;
        LL sumb = 0;
        for (int i = 1; i <= n; i ++ ) read(a[i]), mina = min(mina, a[i]);
        for (int i = 1; i <= n; i ++ ) scanf("%d", &b[i]), sumb += b[i];

        if (sumb <= m) {
            write(mina + ((I128) 1 << k) - 1);
            puts("");
            continue;
        }
        
        for (int i = 1; i <= n; i ++ ) insert(i);

        // for (int i = 1; i <= idx; i ++ ) printf("%lld\n", bsum[i]);

        res = 0;
        dfs(1, k - 1, INF, 0ll, (I128) 0, (I128) 0);

        write(res);
        puts("");
    }
}

蒟蒻犯的若至错误

  • Trie 写挂了
  • Trie 写挂了 \(\times 2\)
  • INF 开小了

标签:cur,idx,rs,省选,luoguP10218,int,ans,I128,联考
From: https://www.cnblogs.com/XiaoJuRuoUP/p/-/luoguP10218

相关文章

  • 省选动态规划专题
    消失之物发现背包顺序无关,那么就支持\(O(n)\)撤销任何一个物品。时间复杂度\(O(nm)\)。当然也有唐氏的线段树分治和多项式解法,强行带个\(\log\)。code#include<bits/stdc++.h>#include<bits/extc++.h>//usingnamespace__gnu_pbds;//usingnamespace__gnu_cxx;usingn......
  • 2024省选联测1
    2024省选联测1题目来源:2024省选联测1\(T1\)HZTG5808.interval\(40pts\)原题:QOJ1173.KnowledgeIs..考虑按照左端点升序排序后反悔贪心。分别维护已经匹配的区间对和未被匹配的区间,若当前区间\(a\)可以和前面剩余的未被匹配的区间匹配则直接匹配;否则尝试找到......
  • 省选联测1
    hahaha,太菜了,成功垫底力。rank3,T1100pts,T20pts,T30pts.T1好像是神必贪心,写了个不知道对不对的做法,反正过了大样例,就这样吧。T2不会,写了个\(2^n\timesn\logm\)的暴力,可能是dpor图论?T3没读懂题。总结:菜。upd:T1过了,T2边权只有0/1我打什么dijkstra啊?T3是送分题?inte......
  • 『联合省选2025集训』『图的连通性进阶』 知识点 总结
    前言若有长风绕旗,那便是我在想你了。这周讲了个图论连通性板块的一些进阶知识,周六全国第一给我们讲了一些树上的问题,感觉树剖板块实现难度较大,后面几道偏思维的题会有些许好转。这里就先写写连通性相关的进阶的一些知识点吧。主要涵盖:耳分解,双极定向,三连通分量和一些重要的......
  • 2020年全国硕士研究生入学统一考试管理类专业学位联考英语(二)试题-纯享题目版
    ......
  • 省选集训 Day 3
    学习了新知识:边三连通,耳分解,双极定向下面是一些基础练习。linkA挺不错的问题。考虑将一个点作为\(G_0\),一个个加入耳来构造边双连通图。容易设计\(f_S\)并枚举子集转移,复杂度\(O(3^nn^2)\)左右。太劣了,考虑将拼耳的过程纳入DP。设\(f_{S,j,k}\)为当前图已经填入......
  • 省选集训 Day 4
    省选集训Day4linkA联合省选2023D1T2纯树形dp做法B感觉是套路题啊。首先可以反应过来求出取到每个\(v\)的最大\(k\),然后做后缀\(\min\)使用二分查找算答案。将一条边\((x,y)\)的边权设为\(\gcd(w_x,w_y)\)枚举\(\gcd\),拿出所有边权是其倍数的边出来建立一个新的......
  • 省选模拟赛 1
    link期望100+100+15,实际100+90+0,被卡常+写错文件名。A可以发现一个简单的dp,也就是设\(f_{l,r}\)为删光\([l,r]\)的答案,那么显然有:\[f_{l,r}=\min(\max(f_{l+1,r-1},w_{l,r}),\min_k\max(f_{l,k},f_{r,k}))\]现在是\(O(n^3)\)的,我们需要优化。我们发现,这支持二分答......
  • 『联合省选2025集训』『省选模拟赛1』 Day5 总结
    前言落日沉溺于橘色的海,晚风沦陷于赤诚的爱。省流:省选集训,\(\texttt{BZ13}\)人,\(50+20+0=70\),\(\texttt{rk11}\),因为有两个跟我并列倒一,真的糖丸了,低年级的也考不过。T1不会用\(\text{Bitset}\)查询最低位的\(1\),即便不会,\(\mathcal{O}(\frac{n^3\times\log(n^2)}{\o......
  • 省选训练赛 #11 记录
    个人认为B和C质量都很高。B一个数轴上有\(n\)个炸弹,第\(i\)个炸弹位于\(X_i\),爆炸半径为\(R_i\),权值为\(v_i\),这些炸弹的排布有两个性质:若炸弹\(x\)可以直接或间接引爆炸弹\(y\),那么\(y\)一定不能直接或间接引爆炸弹\(x\)。定义炸弹序列\(a_1,a_2,\do......