Codeforces Round #482 (Div. 2)

D. Kuro and GCD and XOR and SUM

字典树真好玩。。。

牛老板提供的思路:建1e5个 字典树,每个数插入到以它的因子为根所在的字典树中,这样就实现了整除,当然gcd(k, x) = k是必须的

然后如何保证v + x <= s 和 v ^ x 最大呢?

对于v + x <= s,我们可以维护01字典树中,经过每个节点的最小值,这样我们在访问每个节点时,直接min + x <= s 判断是否成立即可, 不成立就不用往下走了,因为最小值都不成立。

对于v ^ x最大,就是一般字典树思路了,~x与字典树比较选相同的位走,并且同时判断不等式条件就可以啦。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 50;
struct node
{
    int next[2];
    int v;
};
node tree[maxn * 200];
int root[maxn];
int sz = 1;
void build(int p, int x)
{
    if(!root[p]) root[p] = sz++;
    int tmp = root[p];
    for(int i = 20; i >= 0; i--)
    {
        int id = (x >> i) & 1;
        if(tree[tmp].next[id] == 0)
        {
            memset(tree[sz].next, 0, sizeof(tree[sz].next));
            tree[sz].v = 1e6;
            tree[tmp].next[id] = sz++;
        }
        tmp = tree[tmp].next[id];
        tree[tmp].v = min(tree[tmp].v, x);
    }
}
void match(int k, int s, int x)
{
    int par = root[k];
    if(par == 0)
    {
        printf("-1
");
        return;
    }
    int fx = ~x;
   // printf("%d
", ((fx >> 1) & 1));
    int ans = 0;
    int flag = 0;
    for(int i = 20; i >= 0; i--)
    {
        int id = (fx >> i) & 1;
        if(tree[par].next[id] && (tree[tree[par].next[id]].v + x) <= s) ///维护最小值,表示最少存在这样的解
        {
            ans = tree[tree[par].next[id]].v;
            par = tree[par].next[id];
        }
        else if(tree[par].next[1 - id] && (tree[tree[par].next[1 - id]].v + x) <= s)
        {
            ans = tree[tree[par].next[1 - id]].v;
            par = tree[par].next[1 - id];
        }
        else
        {
            flag = 1;
            break;
        }
    }
    if(flag || (!ans))
    {
        printf("-1
");
    }
    else
    {
        printf("%d
", ans);
    }
}
int gcd(int a, int b)
{
    return b == 0 ? a : gcd(b, a % b);
}
int main()
{
    memset(root, 0, sizeof(root));
    int q; scanf("%d", &q);
    while(q--)
    {
        int t;
        scanf("%d", &t);
        if(t == 1)
        {
            int u; scanf("%d", &u);
            for(int i = 1; i * i <= u; i++)
            {
                if(u % i == 0) ///i是u的因子
                {
                    build(i, u);
                    build(u / i, u);
                }
            }
        }
        else
        {
            int x, k, s;
            scanf("%d %d %d", &x, &k, &s);
            int g = gcd(k, x);
            if(g != k)
            {
                printf("-1
");
            }
            else
            {
                match(k, s, x);
            }
        }
    }
}
Code
原文地址:https://www.cnblogs.com/littlepear/p/9041937.html