• HDU2588:GCD(欧拉函数的应用)


    题目链接:传送门 

    题目需求:Given integers N and M, how many integer X satisfies 1<=X<=N and (X,N)>=M.(2<=N<=1000000000, 1<=M<=N),

    题目解析:

       求(X,N),不用想要分解N的因子,分解方法如下,我一开始直接分解for(int i=2;i<=n/2;i++),这样的话如果n==10^9,那么直接超时,因为这点失误直接浪费了一中午

    的时间,要这么分解for(int i=2;i*i<=n;i++)具体请在代码里面看,然后开始求(X,N)>=M。

    这才是核心:

    要求有多少个 i 满足gcd(i, N) = d(1<=i<=N)
    如果gcd(i, N) = d,则gcd(i/d, N/d) = 1
    由于i <= N,所以 i/d <= N/d,转化为求多少个不大于N/d的数与N/d互质,而这就是欧拉函数
    所以有phi(N/d)个 i 满足gcd(i, N) = d,所以求gcd(i,N)>=M,就是求N的因子中大于等于M的欧拉函数值,

    即gcd(N/d1)+gcd(N/d2)+...+gcd(N/dn),其中di>=M,且为N的因子。

    直接写:(都是15ms,这是后台数据的问题,数据多了肯定还是打表快)

    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <math.h>
    typedef __int64 ll;
    using namespace std;
    ll n,m,sum,top,key,M,coun,i;
    int f[1001];
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            sum=1;
            top=0;
            scanf("%I64d%I64d",&n,&m);
            for(i=2; i*i<n; i++)
            {
                if(n%i==0)
                {
                    f[top++]=i;
                    f[top++]=n/i;
                }
            }
            if(i*i==n)//千万别忘了这一句,如16=4*4
            {
               f[top++]=i;
            }
            sort(f,f+top);
            key=-1;
            for(i=0; i<top; i++)
            {
                if(f[i]>=m)
                {
                    key=i;
                    break;
                }
            }
            if(key==-1)
            {
                printf("1
    ");
                continue;
            }
            for(i=key; i<top; i++)
            {
                 M=n/f[i];
                 coun=n/f[i];
                for(ll z=2; z*z<=M; z++)
                {
                    if(M%z==0)
                    {
                        coun-=coun/z;
                        M/=z;
                        while(M%z==0)
                            M/=z;
                    }
                }
                if(M!=1) coun-=coun/M;
                sum+=coun;
            }
            printf("%I64d
    ",sum);
        }
        return 0;
    }

    一部分欧拉值打表:

    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <math.h>
    typedef __int64 ll;
    using namespace std;
    ll n,m,sum,top,key,i;
    int phi[10006],f[1001];
    void init()
    {
        memset(phi,0,sizeof(phi));
        phi[1]=1;
        for(int i=2; i<=10000; i++)
        {
            if(!phi[i])
            {
                for(int j=i; j<=10000; j=j+i)
                {
                    if(!phi[j]) phi[j]=j;
                    phi[j]-=phi[j]/i;
                }
            }
        }
    }
    int main()
    {
        int T;
        scanf("%d",&T);
        init();
        while(T--)
        {
            sum=1;
            top=0;
            scanf("%I64d%I64d",&n,&m);
            for(i=2; i*i<n; i++)
            {
                if(n%i==0)
                {
                    f[top++]=i;
                    f[top++]=n/i;
                }
            }
            if(i*i==n)
            {
               f[top++]=i;
            }
            sort(f,f+top);
            for(i=0; i<top; i++)
            {
                if(f[i]>=m)
                {
                    key=i;
                    break;
                }
            }
            if(key==-1)
            {
                printf("1
    ");
                continue;
            }
            for(ll i=key; i<top; i++)
            {
                if(n/f[i]<=10000)
                {
                    sum+=phi[n/f[i]];
                    continue;
                }
                ll M=n/f[i];
                ll coun=n/f[i];
                for(ll z=2; z*z<=M; z++)
                {
                    if(M%z==0)
                    {
                        coun-=coun/z;
                        M/=z;
                        while(M%z==0)
                            M/=z;
                    }
                }
                if(M!=1) coun-=coun/M;
                sum+=coun;
            }
            printf("%I64d
    ",sum);
        }
        return 0;
    }

     大神博客:http://hi.baidu.com/bg1995/item/ef25e3261f584053c38d59a8

  • 相关阅读:
    理性即自由
    解决问题的思路是怎样的?
    联系的结构-深度思考
    思考力,才是真正的第一生产力-快思考、慢思考
    CentOS7在防火墙与端口上的操作
    linux如何查看nginx是否启动
    Git篇
    Git 常用命令总结
    siblings() 获得匹配集合中每个元素的同胞
    Mysql查看版本号的五种方式介绍
  • 原文地址:https://www.cnblogs.com/zhangmingcheng/p/4251127.html
Copyright © 2020-2023  润新知