codeforces 979D - Kuro and GCD and XOR and SUM

标签(空格分隔): Trie树


题目链接

http://codeforces.com/problemset/problem/979/D

题意

给定一个空集合,有两种操作:
一种是往集合中插入一个元素,一种是给三个数\(x,k,s\),问集合中是否存在\(v\),使得\(x\ mod\ k==0\)\(v\ mod\ k==0\),若存在多个满足条件,则输出使得\(v\oplus x\)最大。

分析

首先如果没有整除条件的话,可以维护一个字典树就能解决。
对于这个题我们可以建立\(10^5\)个字典树,编号分别为\(1,2,3....\),编号为\(k\)的字典树为例,我们只向其中插入\(k\)的倍数的元素。
然后每次集合中加入新元素时,我们暴力的把它插入到它所有的因子的字典树中去。
每个元素的因子可以在\(O(nlog(n))\)时间内预处理得到。

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
const int maxn=100050;
struct Trie{
	int ch[maxn*400][2];
	int T[maxn],sz,val[maxn*400];
	Trie(){
	    sz=0;
		for(int i = 1; i < maxn; ++i) T[i]=++sz;
	}
	void insert(int k,int x){
		int u = T[k];
		for(int i = 19; i >= 0; --i){
			int c=(x>>i)&1;
			if(!ch[u][c]) ch[u][c]=++sz,u=sz,val[u]=x;
			else u=ch[u][c],val[u]=min(val[u],x);
		}
	}
	int query(int x,int k,int s){
		if(x%k) return -1;
		int u=T[k];
		for(int i = 19; i >= 0; --i){
			int c=((x>>i)&1^1);
			if(ch[u][c]&&val[ch[u][c]]<=s-x) u=ch[u][c];
			else u=ch[u][c^1];
		}
		if(val[u]>s-x||val[u]==0) return -1;
		return val[u];
	}
}T;
vector<int> v[maxn];
bool vis[maxn];
int main(){
	for(int i = 1; i < maxn; ++i){
		for(int j = i; j < maxn; j+=i){
			v[j].push_back(i);
		}
	}
	int q;
	scanf("%d", &q);
	while(q--){
		int t,x,k,s;
		scanf("%d", &t);
		if(t&1){
			scanf("%d", &x);
			if(vis[x]) continue;
			for(auto c:v[x]) T.insert(c,x);
		}
		else{
			scanf("%d%d%d", &x,&k,&s);
			printf("%d\n", T.query(x,k,s));
		}
	}
}

posted @ 2018-05-21 20:14  sciorz  阅读(294)  评论(0编辑  收藏  举报