CF979D Kuro and GCD and XOR and SUM(01Trie)
看到异或最大值,很容易想到01trie
现在的问题是多了几个约束条件。我们观察第一个条件,就是要求v的大小,这个很好维护,只需要维护最小值就行。
问题是第二个条件,第一步我们发现这个条件等价于x%k==0&&v%k==0.
简单的证明一下,首先如果一个数整除两个数的最大公约数,如果某一个数不是他的倍数,显然不可能。
当他们是他的倍数,那么他们的最大公约数也能整除这个数,最大公约数永远会包括这个k。
现在的问题是如何建trie,这里需要一些思维,发现数不会大于1e5,因此我们对于每个数都建一个trie
而插入的时候,把这个数插进他的所有约数当中,这个约数需要预处理。这样我们选择的k,答案就在k的trie上,之后就是贪心异或
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pll; const int N=1e5+10; const int inf=1e9; int tr[N*18*18][2],rt[N]; int mi[N*18*18]; int vis[N]; int st[N]; int cnt; vector<int> d[N]; void init(){ int i,j; for(i=1;i<=1e5;i++){ for(j=i;j<=1e5;j+=i){ d[j].push_back(i); } } } void insert(int rt,int x){ int p=rt; mi[p]=min(mi[p],x); for(int i=18;i>=0;i--){ int sign=x>>i&1; if(!tr[p][sign]){ tr[p][sign]=++cnt; } p=tr[p][sign]; mi[p]=min(mi[p],x); } } int query(int k,int x,int s){ int p=rt[k]; if(x%k!=0||mi[p]+x>s) return -1; ll ans=0; for(int i=18;i>=0;i--){ int sign=x>>i&1; if(tr[p][!sign]&&mi[tr[p][!sign]]+x<=s){ ans+=((sign^1)<<i); p=tr[p][!sign]; } else{ ans+=(sign<<i); p=tr[p][sign]; } } return ans; } int main(){ ios::sync_with_stdio(false); init(); int q; cin>>q; int mx=N*18*18; for(int i=0;i<mx;i++){ mi[i]=inf; } while(q--){ int opt; cin>>opt; if(opt==1){ int u; cin>>u; if(st[u]) continue; st[u]=1; for(auto x:d[u]){ if(!vis[x]){ rt[x]=++cnt; vis[x]=1; } insert(rt[x],u); } } else{ int x,k,s; cin>>x>>k>>s; cout<<query(k,x,s)<<endl; } } return 0; }
没有人不辛苦,只有人不喊疼