【Trie】【枚举约数】Codeforces Round #482 (Div. 2) D. Kuro and GCD and XOR and SUM
题意:
给你一个空的可重集,支持以下操作:
向其中塞进一个数x(不超过100000),
询问(x,K,s):如果K不能整除x,直接输出-1。否则,问你可重集中所有是K的倍数的数之中,小于等于s-x,并且与x异或结果最大的数是多少(如果不存在这样的数,也输出-1)。
建立100000个二进制Trie,第i个Trie中存储i的所有倍数。
查询的时候,在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; }
——The Solution By AutSky_JadeK From UESTC
转载请注明出处:http://www.cnblogs.com/autsky-jadek/