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

原文地址:https://www.cnblogs.com/zhangmingcheng/p/4251127.html