Codeforces Round #482 (Div. 2) D. Kuro and GCD and XOR and SUM(数学+01字典树)(好题)

题目链接
在这里插入图片描述
在这里插入图片描述
题意:有n个操作,操作1代表往集合里面加入一个数字x,操作2会给出三个数字x,k,s,然后对于每一个2操作,题目有一个询问,要求从集合中找一个数vv满足下面的条件:
gcd(x,v)%k==0
x+v≤s
使x⊕v的值最大
思路:对于第一个条件我们可以建1e5棵字典树,第i棵字典撒插的就是所有的i的倍数,因为v肯定是k的倍数,所以我们最后查询的时候就在第k棵字典树上查询。那么第二个和第三个条件的话只要在01字典树求异或的模板加个判断大小的条件就行了。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+50;
int tree[maxn*400][2],sum[maxn*400],pos[maxn],cnt=0;
vector<int>g[maxn];
void insert(int id,int x)
{
	int u=pos[id];
	for(int i=31;i>=0;--i)
	{
		int t=(((1LL<<i)&x)?1:0);
		if(!tree[u][t]) tree[u][t]=++cnt,sum[tree[u][t]]=x;
		else sum[tree[u][t]]=min(sum[tree[u][t]],x);
		u=tree[u][t];
	}
	sum[u]=min(sum[u],x);
}
int query(int x,int id,int s)
{
	if(x%id!=0) return -1;
	int u=pos[id];
	for(int i=31;i>=0;--i)
	{
		int t=(((1LL<<i)&x)?1:0);
		if(tree[u][t^1]&&sum[tree[u][t^1]]<=s-x) u=tree[u][t^1];
		else if(sum[tree[u][t]]<=s-x) u=tree[u][t];
		else return -1;
	}
	return sum[u];
}
int main()
{
	int q,op,x,k,s;
	memset(sum,0x3f3f3f3f,sizeof(sum));
	for(int i=1;i<maxn;++i)
	{
		pos[i]=++cnt;
		for(int j=i;j<maxn;j+=i)
		g[j].push_back(i);
	 } 
	 scanf("%d",&q);
	 while(q--)
	 {
	 	scanf("%d",&op);
	 	if(op==1)
	 	{
	 		scanf("%d",&x);
	 		for(int to:g[x]) insert(to,x);
		 }
		 else scanf("%d %d %d",&x,&k,&s),printf("%d\n",query(x,k,s));
	 }
 } 
发布了283 篇原创文章 · 获赞 0 · 访问量 7313

猜你喜欢

转载自blog.csdn.net/qq_42479630/article/details/105057871