题目链接:http://codeforces.com/contest/979/problem/D
参考大神博客:https://www.cnblogs.com/kickit/p/9046953.html:
解题心得:
- 题目给了你很多条件,具体起来就是输入三个数x,k,s,在数列中找到一个数num,要求:1. GCD(x, num)%k == 0; 2. x + num <= s;3. num异或x最大
- 刚开始一看数据量这么大,条件这么多怎么搞。其实前面两个条件是用来剪枝的。首先可以开很多个set,将每一个数放在他因子的set中,这样在面对第一个条件的时候就可以直接在set[k]里面找目标数。然后我们从set[k]中找最大的num,使得x+num<=s,这里寻找第一个数可以在set中使用二分,然后向前便利记录下异或值的Max,如果遍历过程中num+x<=Max直接跳出,因为两个数的异或值<=两个数的和。
- 其实在寻找异或值最大的问题其实就是用Trie,这个题也可以用Trie,但是节点太多了,只能动态开辟内存,每次new内存速度太慢了。
按照题意剪枝代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 2e5+100; 4 set <int> se[maxn]; 5 set <int> :: iterator iter; 6 7 int main() { 8 int n; 9 scanf("%d",&n); 10 while(n--) { 11 int ope; 12 scanf("%d",&ope); 13 if(ope == 1) { 14 int num; 15 scanf("%d",&num); 16 int sq = sqrt(1.0*num); 17 for(int i=1;i<=sq;i++) { 18 if(num%i == 0) { 19 se[i].insert(num); 20 se[num/i].insert(num); 21 } 22 } 23 } else { 24 int x,k,s,ans = -1, Max = -1; 25 scanf("%d%d%d",&x,&k,&s); 26 if(x%k) { 27 printf("-1 "); 28 continue; 29 } 30 iter = se[k].upper_bound(s-x); 31 if(se[k].empty() || iter==se[k].begin()) { 32 printf("%d ", ans); 33 continue; 34 } 35 iter--; 36 while(iter!=se[k].begin()) { 37 if(*iter + x < Max) 38 break; 39 int temp = (*iter)^x; 40 if(temp > Max){ 41 Max = temp; 42 ans = *iter; 43 } 44 iter--; 45 } 46 int temp = (*iter)^x; 47 if(temp > Max) 48 ans = *iter; 49 printf("%d ",ans); 50 } 51 } 52 return 0; 53 }
Trie代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 1e5+100; 4 5 struct node{ 6 int Min; 7 node* bit[2]; 8 node() { 9 bit[0] = bit[1] = nullptr; 10 Min = maxn; 11 } 12 }; 13 14 node* head[maxn]; 15 int n; 16 17 set <int> se[maxn]; 18 set <int> ::iterator iter; 19 20 void init() { 21 scanf("%d",&n); 22 for(int i=1;i<maxn;i++) { 23 for(int j=i;j<maxn;j+=i){ 24 se[j].insert(i); 25 } 26 } 27 for(int i=0;i<maxn;i++) 28 head[i] = new node(); 29 } 30 31 void insert_tree(int va, int u) { 32 node *cur = head[va]; 33 cur->Min = min(cur->Min, u); 34 for(int i=18;i>=0;i--) { 35 int b = (u>>i)&1; 36 if(cur->bit[b] == nullptr){ 37 cur->bit[b] = new node(); 38 cur = cur->bit[b]; 39 cur->Min = min(cur->Min, u); 40 } else { 41 cur = cur->bit[b]; 42 cur->Min = min(cur->Min, u); 43 } 44 } 45 } 46 47 int query(int x, int k, int s) { 48 if(head[k]->Min > s -x || x%k != 0) 49 return -1; 50 node *cur; 51 cur = head[k]; 52 int res = cur->Min; 53 for(int i=18;i>=0;i--){ 54 int b = (x>>i)&1; 55 int Xor = b^1; 56 if(cur->bit[Xor] != nullptr && cur->bit[Xor]->Min + x <= s) { 57 res = cur->bit[Xor]->Min; 58 cur = cur->bit[Xor]; 59 } else { 60 cur = cur->bit[b]; 61 res = cur->Min; 62 } 63 } 64 return res; 65 } 66 67 int main() { 68 init(); 69 while(n--) { 70 int ope; 71 scanf("%d",&ope); 72 if(ope == 1) { 73 int u; 74 scanf("%d",&u); 75 for(iter=se[u].begin();iter!=se[u].end();iter++) { 76 int temp = *iter; 77 insert_tree(temp, u); 78 } 79 } else { 80 int x, k, s; 81 scanf("%d%d%d",&x,&k,&s); 82 int ans = query(x, k, s); 83 printf("%d ",ans); 84 } 85 } 86 return 0; 87 }