題意:spa
給你一個空的可重集,支持如下操做:blog
向其中塞進一個數x(不超過100000),it
詢問(x,K,s):若是K不能整除x,直接輸出-1。不然,問你可重集中全部是K的倍數的數之中,小於等於s-x,而且與x異或結果最大的數是多少(若是不存在這樣的數,也輸出-1)。io
創建100000個二進制Trie,第i個Trie中存儲i的全部倍數。class
查詢的時候,在Trie上從高位到低位貪心地找,若是從根到當前點的路徑造成的數剛好與s-x相等,要從當前點進行一次dfs統計,看看當前子樹中是否存在不超過s-x的數,若是不存在,返回-1。若是當前位剛好小於s-x的當前位,開啓一個「限制解除」標記。若是已經開啓了此標記,直接返回該點的子樹大小是否大於零便可,沒必要dfs統計。若是沒有開啓此標記,而且當前位大於s-x的當前位,直接返回-1便可。二進制
#include<cstdio> using namespace std; struct Node{ int ch[2]; Node(){ ch[0]=ch[1]=0; } }; Node* trees[100005]; int *sz[100005]; int tot[100005]; bool vis[100005]; void Insert(int o,int x){ int U=1; ++sz[o][1]; for(int i=18-1;i>=0;--i){ if(!trees[o][U].ch[(x>>i)&1]){ trees[o][U].ch[(x>>i)&1]=++tot[o]; } U=trees[o][U].ch[(x>>i)&1]; ++sz[o][U]; } } void Insert(int x){ if(vis[x]){ return; } vis[x]=1; for(int i=1;i*i<=x;++i){ if(x%i==0){ if(i!=x/i){ Insert(i,x); Insert(x/i,x); } else{ Insert(i,x); } } } } bool jiechu; bool check(int o,int Bit,int lim,int i,int U){ if(jiechu || Bit<(lim>>(i-1)&1)){ return sz[o][U]; } if(Bit>(lim>>(i-1)&1)){ return 0; } int sum=0; for(--i;i>=1;--i){ int limBit=(lim>>(i-1)&1); if(limBit==1){ sum+=sz[o][trees[o][U].ch[0]]; } U=trees[o][U].ch[limBit]; } sum+=sz[o][U]; return sum>0; } int query(int o,int lim,int W){ jiechu=0; int res=0,U=1; for(int i=18;i>=1;--i){ int Bit=((W>>(i-1)&1)^1); if(!check(o,Bit,lim,i,trees[o][U].ch[Bit])){ Bit^=1; if(!check(o,Bit,lim,i,trees[o][U].ch[Bit])){ return -1; } } if(Bit<(lim>>(i-1)&1)){ jiechu=1; } res+=(1<<(i-1))*Bit; U=trees[o][U].ch[Bit]; } return res; } int q; int main(){ int op,x,K,s; for(int i=1;i<=100000;++i){ tot[i]=1; trees[i]=new Node[20*100000/i]; sz[i]=new int[20*100000/i]; for(int j=0;j<20*100000/i;++j){ sz[i][j]=0; } } scanf("%d",&q); for(;q;--q){ scanf("%d%d",&op,&x); if(op==1){ Insert(x); } else{ scanf("%d%d",&K,&s); if(x%K!=0 || s<=x){ puts("-1"); continue; } printf("%d\n",query(K,s-x,x)); } } return 0; }