Codeforces 979D Kuro and GCD and XOR and SUM(字典树)

题目链接:Kuro and GCD and XOR and SUM

题意

初始有一个空的集合,有 q q 次操作,每次操作有两种选择:

  1. 给定 ui,表示将 ui u i 加入到集合中;

    • 给定 xi,ki,si x i , k i , s i ,从集合中找到一个整数 v v ,要求 v 满足条件 ki|gcd(xi,v),xi+vsi k i | gcd ( x i , v ) , x i + v ≤ s i xiv x i ⊕ v 的值最大。

输入

第一行为一个整数 q (2q105) q   ( 2 ≤ q ≤ 10 5 ) ,接下去 q q 行,每行可以是以下两种格式:

  1. 第一个数字为 1,后面跟着一个整数 ui (1ui105) u i   ( 1 ≤ u i ≤ 10 5 ) ,表示第一种操作;

    • 第一个数字为 2 2 ,后面跟着三个整数 xi,ki.si,表示操作 2 2

输出

对于每次操作 2,如果可以找到合法的 v v ,则输出 v 的值,否则输出 1 − 1

样例

输入
5
1 1
1 2
2 1 1 3
2 1 1 2
2 1 1 1
输出
2
1
-1
提示
1.向集合中加入数字 1 1 ,则集合为 {1}
2.向集合中加入数字 2 2 ,则集合为 {1,2}
3. 1|gcd(1,1),1+12,11=0;1|gcd(1,2),1+23,12=3 1 | gcd ( 1 , 1 ) , 1 + 1 ≤ 2 , 1 ⊕ 1 = 0 ; 1 | gcd ( 1 , 2 ) , 1 + 2 ≤ 3 , 1 ⊕ 2 = 3 因此答案为 2 2
4.只有 1 满足前两个条件,因此答案为 1 1
5.无法找到满足条件的数字,因此答案为 1
输入
10
1 9
2 9 9 22
2 3 3 18
1 25
2 9 9 20
2 25 25 14
1 20
2 26 26 3
1 14
2 20 20 9
输出
9
9
9
-1
-1
-1
题解

ki k i 不能整除 xi x i ,直接输出 1 − 1 ,如果可以整除,答案就在 ki k i 的所有倍数中查找,建立 105 10 5 棵字典树,第 i i 棵字典树存的是集合中 i 的所有倍数,这样每加入一个数字 ui u i ,就将 ui u i 加入到他的所有约数的字典树中,对于每次 2 2 操作,直接在第 k 棵字典树上查找满足条件的答案即可,需要 O(nlnn) O ( n ln ⁡ n ) 地预处理所有约数。

过题代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
#include <cmath>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <functional>
#include <algorithm>
using namespace std;

#define LL long long
const int maxn = 100000 + 100;
vector<vector<int> > tree;
vector<int> Min;
int cnt;
bool vis[maxn];
struct Trie {
    int root;

    int creat(int x) {
        int ret = cnt;
        ++cnt;
        tree.push_back(vector<int>(2, -1));
        Min.push_back(x);
        return ret;
    }

    void Init() {
        root = creat(1000000000);
    }

    int id(int x, int Index) {
        return ((x >> (20 - Index)) & 1);
    }

    void add(int x) {
        int pos = root;
        Min[pos] = min(Min[pos], x);
        for(int i = 0; i <= 20; ++i) {
            int w = id(x, i);
            if(tree[pos][w] == -1) {
                tree[pos][w] = creat(x);
            }
            pos = tree[pos][w];
            Min[pos] = min(Min[pos], x);
        }
    }

    int query(int x, int s) {
        int ret = 0;
        int num = 0;
        int pos = root;
        for(int i = 0; i <= 20; ++i) {
            int w = !id(x, i);
            if(tree[pos][w] == -1 || Min[tree[pos][w]] > s) {
                w = !w;
            } else {
                ret |= (1 << (20 - i));
            }
            if(tree[pos][w] == -1 || Min[tree[pos][w]] > s) {
                return -1;
            }
            num |= (w << (20 - i));
            pos = tree[pos][w];
        }
        return num;
    }
};
int q, command, x, k, s;
Trie t[maxn];
vector<int> fac[maxn];

int main() {
    #ifdef LOCAL
    freopen("test.txt", "r", stdin);
//    freopen("10.out", "w", stdout);
    #endif // LOCAL

    for(int i = 1; i < maxn; ++i) {
        t[i].Init();
        for(int j = i; j < maxn; j += i) {
            fac[j].push_back(i);
        }
    }
    scanf("%d", &q);
    for(int i = 0; i < q; ++i) {
        scanf("%d", &command);
        if(command == 1) {
            scanf("%d", &x);
            if(vis[x]) {
                continue;
            }
            vis[x] = true;
            int len = fac[x].size();
            for(int j = 0; j < len; ++j) {
                int num = fac[x][j];
                t[num].add(x);
            }
        } else {
            scanf("%d%d%d", &x, &k, &s);
            if(x % k != 0 || s <= x) {
                printf("-1\n");
            } else {
                printf("%d\n", t[k].query(x, s - x));
            }
        }
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值