• 《算法竞赛进阶指南》0x32约数 解公因数以及公倍数方程


    题目链接:https://www.acwing.com/problem/content/202/

    求解同时满足gcd(a0,x)=a1 和 lcm(b0,x)=b1的x的个数

    解法是处理出b1所有的约数,逐一检查是否满足上述两个方程,由于采用试除法时间复杂度到了O(n*sqrt(b1)),大约是1e8,无法再给定的时间内通过所有的样例,所以考虑预处理出质因数之后再对b1进行分解质因数,在[1,sqrt(b1)]之间最多只有sqrt(b1)/logsqrt(b1)个质数,所以时间复杂度大约是O(n*sqrt(b1)/logb1),大约是1e7左右,然后使用dfs得出所有的约数,在2e9范围内拥有约数最多的数拥有的约数大约就是1600个,所以dfs的分支是不多的,时间复杂度忽略。然后就是检验过程了,一个数N大约有logN个约数,检验中用到了两次gcd函数,这个函数的时间复杂度有证明是O(logn)的,所以总的时间复杂度就是O(n*sqrt(b1)/logb1+log^2 n)。可以在指定的时间内求解这个问题。

    代码:

    #include<iostream>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    using namespace std ;
    #define maxn 45000
    typedef long long ll;
    pair<int,int> factor[50];
    vector<int> prime;
    bool v[maxn+10];
    int cntf;
    
    int divider[maxn],cntd;
    
    int gcd(int a,int b){
        return b?gcd(b,a%b):a;
    }
    void get_primes(int n){
        memset(v,0,sizeof(v));
        for(int i=2;i<=n;i++){
            if(!v[i])prime.push_back(i);
            for(int j=i;j<=n/i;j++){
                v[j*i]=1;
            }
        }
    }
    
    void dfs(int now,int p){//枚举b1所有的约数,总共会产生之多1600个分支 
        if(now > cntf){
            divider[cntd++]=p;
            return ;
        } 
        
        for(int i=0;i<=factor[now].second;i++){
            dfs(now+1,p);
            p*=factor[now].first;
        }
    }
    const int M=50;
    int main(){
        get_primes(maxn);//预处理出根号b1范围内的质数 
        
        int a0,b0,a1,b1;
        int n;
        cin>>n;
        while(n--){
            scanf("%d%d%d%d",&a0,&a1,&b0,&b1);
            cntf=0;
            cntd=0;
            int b=b1;
            for(int i=0;prime[i]*prime[i]<=b;i++){
                int p=prime[i];
                if(b%p==0){
                    ++cntf;
                    factor[cntf].first=p;
                    int cnt=0;
                    while(b%p==0)cnt++,b/=p;
                    factor[cntf].second=cnt;
                }
            }
            if(b>1)factor[++cntf]=make_pair(b,1);//最多只有一个大于等于根号b的质数 
            
            dfs(1,1);
            
            int res=0;
            for(int i=0;i<cntd;i++){
                int x=divider[i];
                if(gcd(x,a0)==a1 && 1ll*x*b0/gcd(x,b0)==b1){
                    res++;    
                }
            } 
            printf("%d
    ",res);
        }
        return 0;
    }
  • 相关阅读:
    TCP/IP学习-链路层
    Linux下搭建Wordpress环境
    DiskMgr的限制项
    Win10系统Start Menu上的图标莫名消失
    powershell
    第一个页面的文本域中输入的值怎么在第二个页面中显示
    php 文本框里面显示数据库调出来的资料
    php代码
    php表单提交方法汇总
    php将SQL查询结果赋值给变量
  • 原文地址:https://www.cnblogs.com/randy-lo/p/13179728.html
Copyright © 2020-2023  润新知