Codeforces 979D (STL set)(不用Trie简单AC)

本文介绍了一种解决特定集合操作问题的方法,包括插入元素和查询满足特定数论条件的元素。利用C++ STL set存储能被特定数整除的元素,并通过高效算法找到符合条件的最大异或值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题面:

传送门
题目大意:
给定一个空集合,有两种操作:
一种是往集合中插入一个元素x,一种是给三个数x,k,s,问集合中是否存在v,使得gcd(x,v)%k==0,且x+v<=s若存在多个满足条件,则输出使得v⊕x最大的v。

分析:

首先,gcd(x,v)%k==0,由数论知识得该条件等价于x%k==0&&v%k==0
那么,我们怎么快速求出能整除k的v呢
对操作1输入的数x的每个因数,我们建立一个集合
s[i]存储能被i整除的所有x
且由于c++ STL的set的特性,集合内元素从小到大排列,我们可以快速求出x+v<=s的所有v,再从这些值中选出v⊕x最大的v即可

易错细节
1.在set中查找时我们要记得判断集合是否为空
2.注意upper_bound的返回值
3.集合中只有第一个数满足条件时的特判
因为我们是这样倒序遍历集合的 for(;it!=s[k].begin();it--)
所以当集合中只有第一个数满足条件时,it=s[k].begin(),会直接跳出循环
在循环结尾做一下特判就可以了

时间复杂度分析:
操作1时间复杂度 O(nlog2n) O ( n l o g 2 n )
操作2时间复杂度 O(log2n O ( l o g 2 n

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set> 
#include<cmath>
#define maxn 100005
using namespace std;
set<int>s[maxn]; 
int n;
void div(int x){//分解因数,并将x插入每个因数对应的集合
    int sq=(int)sqrt(x);
    for(int i=1;i<=sq;i++){
        if(x%i==0){
            s[i].insert(x);
            s[x/i].insert(x);
        }
    }
}
int get_ans(int x,int k,int maxs){
    if(x%k!=0) return -1;
    set<int>::iterator it;
    if(s[k].empty()) return -1;//集合为空的特判
    it=s[k].upper_bound(maxs-x);//查找x+v<=s的最大v (准确的说,是v的下标+1,因为upper_bound的返回值)
    if(it==s[k].begin()) return -1;
    it--;//由上知要-1
    int ans=-1,sum=-1;
    for(;it!=s[k].begin();it--){//从大到小找v⊕x最大的v
        int v=*it;
        if(sum>x+v) break;//因为v⊕x<=v+x
        if(sum<(x^v)){
            ans=v;
            sum=x^v;
        }
    }
    if(sum<(x^*it)) ans=*it;//只有第一个数满足条件时的特判
    return ans;
}
int main(){
    int cmd,x,k,s;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&cmd);
        if(cmd==1){
            scanf("%d",&x); 
            div(x);
        }else{
            scanf("%d %d %d",&x,&k,&s);
            printf("%d\n",get_ans(x,k,s));
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值