题意:
q次操作:
(1,x)加入x
(2,x,k,s)查询
查询操作:
在已有的数中找到一个数v,满足k∣GCD(x,v),且x+v<=s,同时还要求x异或v的值最大
输出每次查询的结果v,如果找不到满足条件的数就输出-1
数据范围:所有数据<=1e5
思路:
k∣GCD(x,v)意味着gcd(x,v)%k=0,则题目条件转化为x%k=0且v%k=0
如果单是异或最大值可以用01字典树解决。
处理x%k=0且v%k=0:
建立1e5棵字典树,对于每棵树k,只存k的倍数,每次加入x,把x的因子对应字典树都插入x
查询则到k树中找和x异或最大的v就行了,因为k树中只有k的倍数,所以找到的v一定满足v%k=0
注意还有一种情况是x%k!=0,这种情况直接输出-1不用找了。
因为还需要满足x+v<=s,查询操作中有的路径是不能走的,因为可能走之后找到的v一定不满足这个条件,因此插入的时候更新路径上x的最小值,查询的时候就可以判断走某条路径是否满足该条件。
code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=1e5+5;
const int maxd=17;//1e5最多17位
struct Node{
int a[maxm*maxd*15][2],tot;
int rt[maxm];
int val[maxm*maxd*15];
void init(){
tot=0;
for(int i=1;i<maxm;i++){
rt[i]=++tot;
}
}
void add(int x,int k){//把x插入k树下
int node=rt[k];
for(int i=maxd;i>=0;i--){
int v=(x>>i&1);
if(!a[node][v]){
a[node][v]=++tot;
node=a[node][v];
val[node]=x;
}else{
node=a[node][v];
val[node]=min(val[node],x);//因为需要满足x+val<=s,路径取min
}
}
val[node]=x;
}
int ask(int x,int k,int s){//查询
if(x%k)return -1;//这个不加会wa84,题目不保证x%k==0
int node=rt[k];
for(int i=maxd;i>=0;i--){
int v=(x>>i&1);
if(a[node][v^1]&&x+val[a[node][v^1]]<=s){//走满足条件的
node=a[node][v^1];
}else{//
node=a[node][v];
}
}
if(x+val[node]>s||val[node]==0)return -1;
return val[node];
}
}t;
vector<int>fac[maxm];
signed main(){
for(int i=1;i<maxm;i++){//预处理每个数的因子
for(int j=i;j<maxm;j+=i){
fac[j].push_back(i);
}
}
t.init();//不要忘了初始化
int q;
cin>>q;
while(q--){
int d;
cin>>d;
if(d==1){//add
int x;
cin>>x;
for(int v:fac[x]){//每个因子的字典树都添加一次
t.add(x,v);
}
}else{//d==2,ask
int x,k,s;
cin>>x>>k>>s;
int ans=t.ask(x,k,s);//在k树下找答案
cout<<ans<<endl;
}
}
return 0;
}