POJ2478 Farey Sequence

题目大意:求1~n区间欧拉函数的个数。

思路:直接欧拉函数的递推式的模板撸过~~做了这道题~~从此不再相信C++编译器了~~尼玛坑爹啊~~这道题~~C++RE,G++轻松撸过~~

关于欧拉函数的递推关系:
假设素数p能整除n,那么
如果p还能整除n / p, PHI(n) = PHI(n / p) * p;
如果p不能整除n / p, PHI(n) = PHI(n / p) * (p - 1);

AC program:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
#define maxn 1000100
typedef __int64 LL; 
LL ee[maxn]; 
void get_euler() 
{
   for(LL i=1;i<=maxn;i++)
     ee[i]=i;
   for(LL i=2;i<=maxn;i+=2)
     ee[i]/=2;
   for(LL i=3;i<=maxn;i+=2)
   {
     if(ee[i]==i) 
     {
       for(LL g=i;g<=maxn;g+=i)
          ee[g]=ee[g]/i*(i-1);           
     }       
   }
   //cout<<ee[1]<<" "<<ee[2]<<endl;
   ee[2]=1; //注意了
   for(LL i=3;i<=maxn;i++)
   {
     ee[i]+=ee[i-1];        
   }       
} 
int main()
{
 get_euler();
 LL m; 
while(cin>>m,m)
{
  cout<<ee[m]<<endl;             
}
//system("pause"); 
return 0;} 

 

 

以下转载:

下面是两种求欧拉函数的不同编程方法:

/*==================================================*\
|递推求欧拉函数phi(i)
\*==================================================*/
for (i = 1; i <= maxn; i++) phi[i] = i;
for (i = 2; i <= maxn; i += 2) phi[i] /= 2;
for (i = 3; i <= maxn; i += 2) if(phi[i] == i) {
for (j = i; j <= maxn; j += i)
phi[j] = phi[j] / i * (i - 1);


/*==================================================*\
|单独求欧拉函数phi(x)
\*==================================================*/
unsigned euler(unsigned x)
{// 就是公式
unsigned i, res=x;
for (i = 2; i < (int)sqrt(x * 1.0) + 1; i++)
if(x%i==0) {
res = res / i * (i - 1);
while (x % i == 0) x /= i; // 保证i一定是素数
}
if (x > 1) res = res / x * (x - 1);
return res;
}

 

另转载一篇有特色的做法:

思路:
在生成素数的同时,完成欧拉函数。
daima:
#include <stdio.h>
#define MAX 1000000
int n,p[MAX],a[MAX];
long long f[MAX];
void prim1(){
    for(int i = 1;i <=MAX;i++)
        p[i] = 0;
    for(int i=1;i<=MAX;i++)
        a[i]=i;
    for(int i = 2;i <=MAX;i++)
    {
        if(!p[i])
        {
            for(int j=i;j<=MAX;j+=i)
            {
                p[j] =1;
                a[j] = a[j]/i*(i-1);
            }
        }
    }
    return ;
}
void prim2(){
  int i;
  prim1();
  f[2]=1;
  for(i=3;i<=MAX;i++)
  {
      f[i]=f[i-1]+a[i];
  }
}
int main(){
    prim2();
while(1)
{
    scanf("%d",&n);
    if(!n)
    break;
  printf("%lld\n",f[n]);
}
return 0;
}

 

 

 

再转一篇用筛选法做的~~给跪了~~我的筛法弱爆了~~

#include<iostream>
using namespace std;
//欧拉函数的应用,注意筛法在欧拉函数中的变型应用
__int64 a[1000002]={0};//存放数的互质个数
__int64 b[1000002]={0};//存放结果,这里有一个递推关系b[i]=b[i-1]+a[i];
__int64 c[1000002]={0};//标记数组
__int64 prime[200002]={0},len,n;
__int64 slove1()//素数筛法
{
     __int64 i,j,temp;    
     len=0;
     for(i=2;i<=1000000;i++)
     {
         if(!c[i])prime[len++]=i;
         for(j=0;j<len&&prime[j]*i<=1000000;j++)
         {
             c[prime[j]*i]=1;//不是质数
             if(i%prime[j]==0)break; //                                 
             }                  
         }    
     }
//如果p还能整除n / p, a(n) = a(n / p) * p;
//如果p不能整除n / p, a(n) = a(n / p) * (p - 1);    
void slove2()
{
     __int64 i,j,k;//欧拉函数进行类似素数筛法的处理   
     a[1]=1;
     for(i=2;i<=1000000;i++)
     {
         if(!c[i])//是质数
         {
            a[i]=i-1;continue;              
            }        
         for(j=0;j<len&&prime[j]*prime[j]<=1000000;j++)
         {
             if(i%prime[j]==0)
             {
                if(i/prime[j]%prime[j]==0)
                {
                   a[i]=prime[j]*a[i/prime[j]];                       
                   }
                else a[i]=(prime[j]-1)*a[i/prime[j]];
                break;//                
                }                                         
             }             
         }
     }
void slove3()
{
     __int64 i,j,k;
     b[2]=1;
     for(i=3;i<=1000000;i++)
     {
         b[i]=b[i-1]+a[i];                  
         }
     }    
int main()
{
     slove1();
     slove2();
     slove3();
     while(scanf("%I64d",&n)!=EOF)
     {
           if(n==0)break;
           printf("%I64d\n",b[n]);                    
           }
     return 0;
     }

 

 

 

再转一篇线性的做法:

#include<iostream>

using namespace std;

const int MAX=1001000;

int pri[MAX/3],pn=0;

char notp[MAX]={0};

int phi[MAX];

__int64 sum[MAX];

void phif(void)

{

    for(int i=2;i<MAX;i++){

        if(notp[i]==0){

            pri[pn++]=i;

            phi[i]=i-1;

        }

        for(int j=0;j<pn&&MAX>pri[j]*i;j++){

            notp[i*pri[j]]=1;

            if(i%pri[j]==0){

                phi[i*pri[j]]=phi[i]*pri[j];

                break;

            }

            else

                phi[i*pri[j]]=phi[i]*phi[pri[j]];

        }

    }

}

int main(void)

{

    phif();

    int n;

    sum[2]=phi[2];

    for(int i=3;i<=1000000;i++)

        sum[i]=sum[i-1]+phi[i];

    while(1){

        scanf("%d",&n);

        if(n==0)

            break;

        printf("%I64d\n",sum[n]);

    }

    return 0;

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值