欧拉函数知识点及其求法模板


欧拉函数

数论,对正整数n,欧拉函数是小于n的正整数中与n互质的数的数目(φ(1)=1) 例如φ(8)=4,因为1,3,5,7均和8互质。

欧拉函数有如下基本定理:

一: 是积性函数,设m与n是互素的正整数,那么;

二: :当n为奇数时,有

三: 设p是素数,a是一个正整数,那么

证明:(

由于表示小于互素数的正整数个数,所以用减去与它不互素的数的个数就行了。

那么小于不互素数的个数就是p的倍数个数,有个。所以定理得证。

)

四: 为正整数n的素数幂分解,那么

 

五: 设n是一个正整数,那么

 

六: 设n 是一个大于2 的正整数,则 φ(n)是偶数


常用的两个定理:


费马小定理:

当p是质数时   a(p-1)≡1(mod p)  : 简化幂运算


欧拉定理:

对于和m互素的x,有xφ(m)≡1(mod m)


直接求法: 适用于求单个 phi值时   此时时间复杂小, 且空间小;

int gphi(int n)
{
    int temp=n;
    for(int i=2;i<=n;i++)
    {
        if(n%i==0)
        {
            temp-=temp/i;
            while(n%i==0)
                n/=i;
        }

    }
    if(n>1)
            temp-=temp/n;
    return temp;
}


模板 求 欧拉函数值;

void get_phi(int n)// p是素数
{
cont=0;
	memset(vis,0,sizeof(vis));
    for(int i=2; i<=n; i++)
	{   
        if(!vis[i])
		{
            p[++cont]=i;
            phi[i] = i-1;   
        }
        for(int j=1; j<=cont && p[j]*i<=n; j++)
		{   
            vis[p[j]*i]=1;
            if(i%p[j]==0)
			{
                phi[i*p[j]] = p[j] * phi[i]; //欧拉函数性质
                break;   
            }
			else phi[i*p[j]] = (p[j]-1) * phi[i];
        }
    }
}

递推法求欧拉函数值:


复杂度 O (nln n)
void iinit()
{
	for(int i=1;i<=N;i++) phi[i]=i;
	for(int i=2;i<=N;i+=2)phi[i]>>=1;
	for(int i=3;i<=N;i+=2){
		if(phi[i]==i)
		{
			for(int j=i;j<=N;j+=i)
				phi[j]=phi[j]-phi[j]/i;
		}
	}
}


看一下应用:

例题一:  POJ 2407 http://poj.org/problem?id=2407

最简单的意思:  求 φ(n)    

直接用第一个:其余的打表模板, 空间占有量太大 n的范围是10^9 次方

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cmath>
#include <cstring>

using namespace std;
typedef long long ll;

int gphi(int n)
{
    int temp=n;
    for(int i=2;i<=n;i++)
    {
        if(n%i==0)
        {
            temp-=temp/i;
            while(n%i==0)
                n/=i;
        }

    }
    if(n>1)
            temp-=temp/n;
    return temp;
}
int main()
{
    int n;
    while(cin>>n&&n)
    {
        cout<<gphi(n)<<endl;
    }
    return 0;
}

例题2 :  POJ 1284  http://poj.org/problem?id=1284

原根:  求 x^i mod p = [1,p-1]     p原根的个数;

  这里用到一个结论     如果p 是素数, 则有 φ(p-1)个原根;

直接和上面的代码一样,  输出 gphi(n-1)即可;'

例题3 : POJ 2478  http://poj.org/problem?id=2478

f2= 1,f3 =3 f4=5, f5 =9 f6=11;

而 前10项  φ值为 1 1 2 2 4 2 6 4 6 4   可以发现 f(n)=  从第二项开始 前φ(n)项的和


所以 递推打表 

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cmath>
#include <cstring>

using namespace std;
typedef long long ll;
const int N=1000011;
ll phi[N+10];
void iinit()
{
	for(int i=1;i<=N;i++) phi[i]=i;
	for(int i=2;i<=N;i+=2)phi[i]>>=1;
	for(int i=3;i<=N;i+=2){
		if(phi[i]==i)
		{
			for(int j=i;j<=N;j+=i)
				phi[j]=phi[j]-phi[j]/i;
		}
	}
	for(int i=3;i<=N;i++)
		phi[i]+=phi[i-1];
}

int main()
{

    int n;
	iinit();
    while(cin>>n&&n)
    {
    	cout<<phi[n]<<endl;
    }
    return 0;
}


posted @ 2017-08-14 16:35  Sizaif  阅读(510)  评论(0编辑  收藏  举报