[lnsyoj2246/luoguCF979D]Kuro and GCD and XOR and SUM

题意

给定集合 S,初始为空,进行 q 次修改或查询操作:修改操作将 x 加入集合;查询操作给定 x,s,k,要求找到满足

maxuS,u+xs,k|gcd(u,x){ux}

的最小的 u

sol

集合、异或、可查可改,可以自然地想到 0/1-Trie
我们假设 k=1,此时不需要考虑 k|gcd(u,x) 的条件,这就是一个有上限的最大异或和问题。我们对每个点记录一个 minn,表示经过这个点的最小值,这样,当找到一个点时,如果 sx>minnu,就不能够进入这个点。
再来考虑 k,我们可以对于每一个可能的 k 值都建立一棵 Trie 树,这样,每次插入的时候,O(n) 地枚举所有约数代表的 Trie 树,在这些 Trie 树中都插入 x。查询的时候直接查找第 k 棵树即可。

代码

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

using namespace std;

const int N = 50000005, K = 20;

int q;
int tr[N][2], minn[N], idx;
unordered_set<int> st;

void ins(int x, int p){
    for (int c = K - 1; c >= 0; c -- ){
        int u = (x >> c) & 1;
        if (!tr[p][u]) tr[p][u] = ++ idx;
        p = tr[p][u];
        minn[p] = minn[p] ? min(minn[p], x) : x;
    }
}

int query(int x, int s, int k){
    int res = 0, p = k;
    for (int c = K - 1; c >= 0; c -- ){
        int u = ((x >> c) & 1) ^ 1;
        int ne = tr[p][u], xne = tr[p][u ^ 1];
        if (ne && minn[ne] <= s - x) res += u << c, p = ne;
        else if (xne && minn[xne] <= s - x) res += (u ^ 1) << c, p = xne;
        else return -1;
    }

    return res ? res : -1;
}

int main(){
    idx = 100000;
    scanf("%d", &q);
    while (q -- ){
        int op, x;
        scanf("%d%d", &op, &x);
        if (op == 1) {
            if (st.find(x) == st.end()){
                for (int i = 1; i * i <= x; i ++ ){
                    if (x % i) continue;
                    ins(x, i);
                    if (i * i != x) ins(x, x / i);
                }
                st.insert(x);
            }
        }
        else {
            int k, s;
            scanf("%d%d", &k, &s);
            if (x % k) puts("-1");
            else printf("%d\n", query(x, s, k));
        }
    }
    return 0;
}
posted @   是一只小蒟蒻呀  阅读(19)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示