• [题解]Hankson的趣味题


    2020.03.10

    题面(点击可查看)

    (1<=n<=2000)

    (1<=a_0,a_1,b_0,b_1<=10^9×2)


    (a,b)=>gcd(a,b),[a,b]=>lcm(a,b)

    首先理解题意。给出数据(a,b,c,d),求满足((a,x)=b,[c,x]=d)的所有x的个数。

    从条件([c,x]=d)入手,我们可以发现x是d的约数。

    于是首先考虑暴力做法,枚举所有x的约数,挨个判断是否满足题目条件,但是不用说,2*1e9的数据铁定T飞。

    那么怎么优化呢?

    我们可以看到,在我们在求每一组d的所有约数的时候,我们都一定花费了(sqrt(d))的时间复杂度,而d的范围又比较大,再加上(n)最大可以到2000,所以我们考虑通过其他方式来求得d的所有约数。

    于是考虑先对d进行质因式分解,把d拆成(d=p_1^{s_1}×p_2^{s_2}×...×p_n^{s_n})的形式,其中p为每个质因子,s为每个质因子的次数。这个比较好求,只需要预先把范围以内的质数全部用线性筛过一遍,然后挨个试除,如果有质数p是d的质因子,那就用while循环求出p的次数s即可。

    另外,需要注意的是,如果在所有的质因子都已经试除完毕,d的值还大于1,说明他自己也是一个质数(不能通过质数相乘得到),再记录一组{p,s}即{d,1}。注意这里的d是已经被试除过很多次了,所以已经不是输入时候的值了,实现的时候要注意最好先把d存储下来在进行试除,这样不会影响到后面的判断。

    接下来我们就可以通过一次暴搜来求得d的所有约数(质因子相乘)并存储下来,作为(a,x)=b,[c,x]=d的x的值的范围,然后枚举判断即可。


    #include<bits/stdc++.h>
    using namespace std;
    int pr[50010],cnt;
    bool st[50010];
    struct node
    {
        int p,s;//质因数和次数
    }f[1610];
    int fcnt;
    void init(int n)
    {
        for(int i=2;i<=n;i++)
        {
            if(!st[i])pr[++cnt]=i;
            for(int j=1;pr[j]*i<=n;j++)
            {
                st[pr[j]*i]=1;
                if(i%pr[j]==0)break;
            }
        }
    }
    int gcd(int a,int b){return b?gcd(b,a%b):a;}
    int lcm(int a,int b){return a/(gcd(a,b))*b;}
    int dv[50010],dcnt;
    void dfs(int u,int p)//质因子数组下标,x
    {
        if(u==fcnt)//搜索结束
        {
            dv[++dcnt]=p;
            return;
        }
        for(int i=0;i<=f[u].s;i++)
        {
            dfs(u+1,p);
            p*=f[u].p;
        }
    }
    int main()
    {
        int n;
        init(50005);
        cin>>n;
        while(n--)
        {
            int a,b,c,d;
            cin>>a>>b>>c>>d;
            fcnt=0;
            int t=d;
            for(int i=1;pr[i]<=t/pr[i];i++)
            {
                int p=pr[i];
                if(t%p==0)
                {
                    int s=0;
                    while(t%p==0)
                    {
                        t/=p,s++;
                    }
                    f[fcnt++]={p,s};
                }
                
            }
            if(t>1)f[fcnt++]={t,1};//t本身也是质数
            dcnt=0;
            dfs(0,1);
            int ans=0;
            for(int i=1;i<=dcnt;i++)
            {
                int x=dv[i];
                if(gcd(a,x)==b&&lcm(c,x)==d)ans++;//当前x合法,答案计数加一
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    

  • 相关阅读:
    20145230《java学习笔记》第十周学习总结
    20145230《java学习笔记》第九周学习总结
    20145230《java程序设计》 第四次实验报告
    20145230《java程序设计》第三次试验报告
    20145230 《Java程序设计》第8周学习总结
    20145230java实验报告二
    20145230《java学习笔记》第七周学习总结
    20145230java实验报告1
    20145230《java程序设计》第6周学习总结
    20145228 《信息安全系统设计基础》第五周学习总结 (2)
  • 原文地址:https://www.cnblogs.com/moyujiang/p/12460210.html
Copyright © 2020-2023  润新知