题目链接: http://codeforces.com/problemset/problem/979/D
题目大意: 先有一个空的数组a, 有n个操作, 维护两种操作。 1操作, 向a数组加入一个数u。 2操作, 在a数组找到一个数v, 满足k | GCD(x, v), v + x <= s, 且v XOR x最大, 输出这个v, 不存在则输出-1。(所有的数组都 <= 10^5)。
思路: 考虑比较暴力的方法。 先建立10^5个trie树, 第i个trie树只考虑数组中能被i整除的a, 每个节点存的是当前子树存在的数的最小值。 预处理10^5范围内每个数的因数, 可以用数倍数的方式, O(nlogn)的复杂度预处理出来。 这样对于一个新加的数, 就是往每个它的因数所对应的trie数中插入它, 查找也就在对应的trie树中和一般的找最大异或值的方法类似。 总的复杂度是O(n(logn)^2)级别的。
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = (int)1e5 + 10;
const int M = 20;
int n;
vector<int > d[N]; bool has[N];
int cnt, rt[N], ch[N * 200][2], mn[N * 200];
int newNode(){
++ cnt;
ch[cnt][0] = ch[cnt][1] = 0;
mn[cnt] = N;
return cnt;
}
void init(){
for (int i = 1; i < N; i ++)
for (int j = 0; j < N; j += i)
d[j].push_back(i);
mn[0] = N;
for (int i = 1; i < N; i ++)
rt[i] = newNode();
}
void insert(int u, int v, int k){
mn[u] = min(mn[u], v);
if (k == -1) return;
int t = (v & (1 << k)) ? 1 : 0;
if (!ch[u][t]){
ch[u][t] = newNode();
}
insert(ch[u][t], v, k - 1);
}
int find(int u, int v, int m, int k){
if (k == -1) return 0;
int t = (v & (1 << k)) ? 1 : 0;
if (mn[ch[u][!t]] <= m){
return find(ch[u][!t], v, m, k - 1) | ((!t) << k);
}
else if (mn[ch[u][t]] <= m){
return find(ch[u][t], v, m, k - 1) | (t << k);
}
else return -1;
}
int main(){
init();
scanf("%d", &n);
for (int i = 1; i <= n; i ++){
int opt, u, k, s, x;
scanf("%d", &opt);
if (opt == 1){
scanf("%d", &u);
if (has[u]) continue;
has[u] = true;
for (int j = 0; j < d[u].size(); j ++)
insert(rt[d[u][j]], u, M);
}
else{
scanf("%d %d %d", &x, &k, &s);
if (x % k != 0){
printf("-1\n");
continue;
}
printf("%d\n", find(rt[k], x, s - x, M));
}
}
return 0;
}