CodeForces - 979D Kuro and GCD and XOR and SUM
题意:两个操作,1向数组中添加一个值x,2询问数组中的值满足所给条件的异或xi之后为最大值的值。
2操作输入xi,ki,si,在数组中找到一个值v满足ki|gcd(xi,v),并且xi+v<=si,在所有满足的v中选一个异或xi之后的最大值。
思路:异或最大,01字典树,而且还不用持久化,因为ki需要可以整除gcd(xi,v),所有只要ki可以整出xi,并且可以整除v即可,这样可以开100000个01字典树,每个字典树的根为root[i],代表可以被i整除的v值都放在以此为根的字典树中,需要动态开点,查询时直接在以root[ki]为根的字典树上找满足条件的值即可。注意输出-1的条件需要考虑全面。至于内存不太会开,RE就加。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int MAX_N=101000;
const int INF=0x3f3f3f3f;
int trie[10*MAX_N*21][2];
int minl[10*MAX_N*21],minx[MAX_N];
int root[MAX_N],tot;
void insert(int k1,int val,int deep){
if(deep<0){
minl[k1]=val;
return;
}
int x=(val>>deep)&1;
if(!trie[k1][x])
trie[k1][x]=++tot;
insert(trie[k1][x],val,deep-1);
if(trie[k1][0])
minl[k1]=min(minl[k1],minl[trie[k1][0]]);
if(trie[k1][1])
minl[k1]=min(minl[k1],minl[trie[k1][1]]);
}
int ask(int k,int deep,int xi,int si){
if(deep<0)
return minl[k];
int x=(xi>>deep)&1;
if(trie[k][x^1]&&minl[trie[k][x^1]]<=si-xi)
return ask(trie[k][x^1],deep-1,xi,si);
else
return ask(trie[k][x],deep-1,xi,si);
}
int main(void){
int q,i,j,x,xi,ki,si,op;
scanf("%d",&q);
memset(minx,INF,sizeof(minx));
memset(minl,INF,sizeof(minl));
//cout<<minl[1314]<<"\n";
for(j=0;j<q;j++){
scanf("%d",&op);
if(op==1){
scanf("%d",&x);
//minx=min(minx,x);
for(i=1;i*i<=x;i++){
if(x%i!=0)
continue;
if(root[i])
insert(root[i],x,19);
else{
root[i]=++tot;
insert(root[i],x,19);
}
if(x<minx[i])
minx[i]=x;
int y=x/i;
if(i==y)
continue;
if(root[y])
insert(root[y],x,19);
else{
root[y]=++tot;
insert(root[y],x,19);
}
if(x<minx[y])
minx[y]=x;
}
}
else{
scanf("%d%d%d",&xi,&ki,&si);
if(xi%ki!=0||minx[ki]>si-xi||!root[ki]){
printf("-1\n");
continue;
}
int ans=ask(root[ki],19,xi,si);
if(ans==INF)
printf("-1\n");
else
printf("%d\n",ans);
}
}
return 0;
}