题目链接:Kuro and GCD and XOR and SUM
题意
初始有一个空的集合,有 q q 次操作,每次操作有两种选择:
- 给定 ,表示将 ui u i 加入到集合中;
- 给定 xi,ki,si x i , k i , s i ,从集合中找到一个整数 v v ,要求 满足条件 ki|gcd(xi,v),xi+v≤si k i | gcd ( x i , v ) , x i + v ≤ s i 且 xi⊕v x i ⊕ v 的值最大。
输入
第一行为一个整数 q (2≤q≤105) q ( 2 ≤ q ≤ 10 5 ) ,接下去 q q 行,每行可以是以下两种格式:
- 第一个数字为 ,后面跟着一个整数 ui (1≤ui≤105) u i ( 1 ≤ u i ≤ 10 5 ) ,表示第一种操作;
- 第一个数字为 2 2 ,后面跟着三个整数 ,表示操作 2 2 。
输出
对于每次操作 ,如果可以找到合法的 v v ,则输出 的值,否则输出 −1 − 1 。
样例
输入 |
---|
5 1 1 1 2 2 1 1 3 2 1 1 2 2 1 1 1 |
输出 |
2 1 -1 |
提示 |
1.向集合中加入数字
1
1
,则集合为 ; 2.向集合中加入数字 2 2 ,则集合为 ; 3. 1|gcd(1,1),1+1≤2,1⊕1=0;1|gcd(1,2),1+2≤3,1⊕2=3 1 | gcd ( 1 , 1 ) , 1 + 1 ≤ 2 , 1 ⊕ 1 = 0 ; 1 | gcd ( 1 , 2 ) , 1 + 2 ≤ 3 , 1 ⊕ 2 = 3 因此答案为 2 2 ; 4.只有 满足前两个条件,因此答案为 1 1 ; 5.无法找到满足条件的数字,因此答案为 。 |
输入 |
---|
10 1 9 2 9 9 22 2 3 3 18 1 25 2 9 9 20 2 25 25 14 1 20 2 26 26 3 1 14 2 20 20 9 |
输出 |
9 9 9 -1 -1 -1 |
题解
若 ki k i 不能整除 xi x i ,直接输出 −1 − 1 ,如果可以整除,答案就在 ki k i 的所有倍数中查找,建立 105 10 5 棵字典树,第 i i 棵字典树存的是集合中 的所有倍数,这样每加入一个数字 ui u i ,就将 ui u i 加入到他的所有约数的字典树中,对于每次 2 2 操作,直接在第 棵字典树上查找满足条件的答案即可,需要 O(nlnn) O ( n ln n ) 地预处理所有约数。
过题代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
#include <cmath>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <functional>
#include <algorithm>
using namespace std;
#define LL long long
const int maxn = 100000 + 100;
vector<vector<int> > tree;
vector<int> Min;
int cnt;
bool vis[maxn];
struct Trie {
int root;
int creat(int x) {
int ret = cnt;
++cnt;
tree.push_back(vector<int>(2, -1));
Min.push_back(x);
return ret;
}
void Init() {
root = creat(1000000000);
}
int id(int x, int Index) {
return ((x >> (20 - Index)) & 1);
}
void add(int x) {
int pos = root;
Min[pos] = min(Min[pos], x);
for(int i = 0; i <= 20; ++i) {
int w = id(x, i);
if(tree[pos][w] == -1) {
tree[pos][w] = creat(x);
}
pos = tree[pos][w];
Min[pos] = min(Min[pos], x);
}
}
int query(int x, int s) {
int ret = 0;
int num = 0;
int pos = root;
for(int i = 0; i <= 20; ++i) {
int w = !id(x, i);
if(tree[pos][w] == -1 || Min[tree[pos][w]] > s) {
w = !w;
} else {
ret |= (1 << (20 - i));
}
if(tree[pos][w] == -1 || Min[tree[pos][w]] > s) {
return -1;
}
num |= (w << (20 - i));
pos = tree[pos][w];
}
return num;
}
};
int q, command, x, k, s;
Trie t[maxn];
vector<int> fac[maxn];
int main() {
#ifdef LOCAL
freopen("test.txt", "r", stdin);
// freopen("10.out", "w", stdout);
#endif // LOCAL
for(int i = 1; i < maxn; ++i) {
t[i].Init();
for(int j = i; j < maxn; j += i) {
fac[j].push_back(i);
}
}
scanf("%d", &q);
for(int i = 0; i < q; ++i) {
scanf("%d", &command);
if(command == 1) {
scanf("%d", &x);
if(vis[x]) {
continue;
}
vis[x] = true;
int len = fac[x].size();
for(int j = 0; j < len; ++j) {
int num = fac[x][j];
t[num].add(x);
}
} else {
scanf("%d%d%d", &x, &k, &s);
if(x % k != 0 || s <= x) {
printf("-1\n");
} else {
printf("%d\n", t[k].query(x, s - x));
}
}
}
return 0;
}