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


    题面:

    传送门
    题目大意:
    给定一个空集合,有两种操作:
    一种是往集合中插入一个元素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)
    操作2时间复杂度 O(log2n

    代码:

    #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
    ",get_ans(x,k,s));
            }
        }
    }
  • 相关阅读:
    TCP Socket服务器编程[转文]
    http协议学习和总结系列[转 ]
    linux C函数大全
    HTTP 协议详解
    Pthread 多线程总结
    linux 中解析命令行参数 (getopt_long用法)
    微软企业库4.1学习笔记(十八)缓存模块6 缓存的设计目的
    微软企业库4.1学习笔记(十七)缓存模块5 缓存的典型用法
    进程和线程的区别
    C#二叉树遍历算法实现浅析
  • 原文地址:https://www.cnblogs.com/birchtree/p/9845837.html
Copyright © 2020-2023  润新知