codeforces 979D(01字典树)

图片来自此博主%%%
感觉博主说的很有道理
在这里插入图片描述
代码来自此博主
↓↓↓↓↓
%%%
↑↑↑↑↑讲解的也挺好

接下来就说说蒟蒻的理解吧

题意:

T次操作
ti=1就将num插入数列(初始数列为空)
ti=2 输入三个数xi,ki,si
就去找当前的数列中是否存在一个数v满足以下条件:
① 使得GCD(xi,v)%ki==0
② xi+v<=si
③ 尽可能使xi异或v的值最大
———————————————————

思路:

(01字典树求最大异或值就不赘述了)
将1到1e5所有的数的约数都放进字典树T[k],在建树的时候,当前节点的值为min(val[u],x)(这里不太懂。。)

查询的时候就是从最大的值往下去找(这样就是两个数的GCD)去找尽可能使xi异或v的值最大,并且满足条件②
好像是这么一回事。。。。
———————————————————

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
const int maxn=100050;
struct Trie{
    int ch[maxn*400][2];
    int T[maxn],sz,val[maxn*400];
    Trie(){
        sz=0;
        for(int i = 1; i < maxn; ++i) T[i]=++sz;//节点初始化
    }
    void insert(int k,int x){
        int u = T[k];
        for(int i = 19; i >= 0; --i){
            int c=(x>>i)&1;
            if(!ch[u][c]) ch[u][c]=++sz,u=sz,val[u]=x;
            else u=ch[u][c],val[u]=min(val[u],x);
        }
    }
    int query(int x,int k,int s){
        if(x%k) return -1;
        int u=T[k];//当前数k的起始节点
        for(int i = 19; i >= 0; --i){
            int c=((x>>i)&1^1);
            if(ch[u][c]&&val[ch[u][c]]<=s-x) u=ch[u][c];
            else u=ch[u][c^1];
        }
        if(val[u]>s-x||val[u]==0) return -1;
        return val[u];
    }
}T;
vector<int> v[maxn];
bool vis[maxn];
int main(){
    for(int i = 1; i < maxn; ++i){
        for(int j = i; j < maxn; j+=i){
            v[j].push_back(i);//将1~1e5的每个数的约数都放进vector
            //v[j][i]代表j%i==0
            //v[j]则为数j在1~1e5的所有约数
        }
    }
    int q;
    scanf("%d", &q);
    while(q--){
        int t,x,k,s;
        scanf("%d", &t);
        if(t&1){
            scanf("%d", &x);
            if(vis[x]) continue;
            for(auto c:v[x]) T.insert(c,x);//相当于java的foreach
        }
        else{
            scanf("%d%d%d", &x,&k,&s);
            printf("%d\n", T.query(x,k,s));
        }
    }
}

——————————————————————————————
新技能get√

  • for(int i = 1; i < maxn; ++i)
      for(int j = i; j < maxn; j+=i){
          v[j].push_back(i);//将1~1e5的每个数的约数都放进vector
          //v[j][i]代表j%i==0
          //v[j]则为数j在1~maxn-1的所有约数
      	}
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值