欧拉函数笔记

欧拉函数

概述

欧拉函数就是对于一个正整数n,小于n且和n互质的正整数(包括1)的个数,记作φ(n) 。
欧拉函数的通式:φ(n)=n*(1-1/p1)(1-1/p2)(1-1/p3)*(1-1/p4)……(1-1/pn)
其中p1, p2……pn为n的所有质因数,n是不为0的整数。φ(1)=1(唯一和1互质的数就是1本身)。

性质

① 当m,n互质时,有phi(mn)= phi(m) * phi(n);
② 若i%p==0,有phi(i*p) = p * phi(i);
③ 对于互质x与p,有x^phi§≡1(mod p),因此x的逆元为x^(phi§-1),即欧拉定理。
(特别地,当p为质数时,phi(p)=p-1,此时逆元为x^(p-2),即费马小定理)
④ 当n为奇数时,phi(2n)=phi(n)
⑤ 若x与p互质,则p-x也与p互质,因此小于p且与p互质的数之和为phi(x)*x/2;
⑥N>1,不大于N且和N互素的所有正整数的和是 1/2 *N *eular(N)。

欧拉筛模板

1.	void eular_()//欧拉筛模板  
2.	{  
3.	    memset(vis,true,sizeof(vis));   
4.	    int cnt=1;  
5.	    vis[1]=false;  
6.	    for(int i=2;i<=N-5;i++)  
7.	    {  
8.	        if(vis[i])  prime[cnt++]=I;
9.	        for(int j=1;j<cnt&&prime[j]*i<=N-5;j++)  
10.	        {  
11.	            vis[prime[j]*i]=false;  
12.	            if(i%prime[j]==0)  
13.	            {  
14.	                break;  
15.	            }  
16.	            //若i为p[j]的倍数,则i=k*p[j],  
17.	            //在和p[j+1]相乘后得出的x=i*p[j+1]=p[j]*k*p[j+1]  
18.	            //则在i=k*p[j+1]时,由于j从小到大,必定经过之前的p[j],会重复计算  
19.	        }  
20.	    }  
21.	}  

欧拉函数模板

1.	int euler(int x)  
2.	{  
3.	    int ans=x;  
4.	    for(int i=2;i*i<=x;i++)//模拟(1-p1)*(1-p2)……过程,pi为x的质因数  
5.	    {  
6.	        if(x%i==0)  
7.	        {  
8.	            ans=ans-ans/i;  
9.	        }  
10.	        while(x%i==0)  
11.	        {  
12.	            x/=i;  
13.	        }  
14.	    }  
15.	    if(x>1) ans=ans-ans/x;//若x不为1,说明仍有一个质因数没有乘  
16.	    return ans;  
17.	}  

线性求欧拉函数

1.	void euler_()  
2.	{  
3.	    memset(vis,true,sizeof(vis));  
4.	    memset(phi,0,sizeof(phi));  
5.	    int cnt=1;  
6.	    vis[1]=false;  
7.	    phi[1]=1;//特判1,gcd(1,1)=1  
8.	    for(int i=2;i<=N-5;i++)  
9.	    {  
10.	        if(vis[i])  
11.	        {  
12.	            prime[cnt++]=i;  
13.	            phi[i]=i-1;  
14.	        }  
15.	        for(int j=1;j<cnt&&prime[j]*i<=N-5;j++)  
16.	        {  
17.	            vis[prime[j]*i]=false;  
18.	            if(i%prime[j]==0)  
19.	            {  
20.	                phi[prime[j]*i]=phi[i]*prime[j];  
21.	                break;  
22.	            }  
23.	            phi[prime[j]*i]=phi[i]*phi[prime[j]];  
24.	            //若i为p[j]的倍数,则i=k*p[j],  
25.	            //在和p[j+1]相乘后得出的x=i*p[j+1]=p[j]*k*p[j+1]  
26.	            //则在i=k*p[j+1]时,由于j从小到大,必定经过之前的p[j],会重复计算  
27.	        }  
28.	    }  
29.	}  

例题

例题1 HDU2824 The Euler function

题目描述
The Euler function phi is an important kind of function in number theory, (n) represents the amount of the numbers which are smaller than n and coprime to n, and this function has a lot of beautiful characteristics. Here comes a very easy question: suppose you are given a, b, try to calculate (a)+ (a+1)+…+ (b)
输入格式
There are several test cases. Each line has two integers a, b (2<a<b<3000000).
输出格式
Output the result of (a)+ (a+1)+…+ (b)
输入样例
3 100
输出样例
3042

思路:线性求欧拉函数模板题

代码

1.	#include<bits/stdc++.h>  
2.	using namespace std;  
3.	typedef long long ll;  
4.	const int N=3e6+10;  
5.	int phi[N];  
6.	bool vis[N];  
7.	int prime[N];  
8.	int sum[N];  
9.	void eular_()//欧拉筛模板  
10.	{  
11.	    memset(vis,true,sizeof(vis));  
12.	    memset(phi,0,sizeof(phi));  
13.	    int cnt=1;  
14.	    vis[1]=false;  
15.	    phi[1]=1;//特判1,gcd(1,1)=1  
16.	    for(int i=2;i<=N-5;i++)  
17.	    {  
18.	        if(vis[i])  
19.	        {  
20.	            prime[cnt++]=i;  
21.	            phi[i]=i-1;  
22.	        }  
23.	        for(int j=1;j<cnt&&prime[j]*i<=N-5;j++)  
24.	        {  
25.	            vis[prime[j]*i]=false;  
26.	            if(i%prime[j]==0)  
27.	            {  
28.	                phi[prime[j]*i]=phi[i]*prime[j];  
29.	                break;  
30.	            }  
31.	            phi[prime[j]*i]=phi[i]*phi[prime[j]];  
32.	            //若i为p[j]的倍数,则i=k*p[j],在和p[j+1]相乘后得出的x=i*p[j+1]=p[j]*k*p[j+1]  
33.	            //则在i=k*p[j+1]时,由于j从小到大,必定经过之前的p[j],会重复计算  
34.	        }  
35.	    }  
36.	}  
37.	int main()  
38.	{  
39.	    int a,b;  
40.	    eular_();  
41.	    while(cin>>a>>b)  
42.	    {  
43.	        ll ans=0;  
44.	       for(int i=a;i<=b;i++) ans+=phi[i];  
45.	       cout<<ans<<endl;  
46.	    }  
47.	    return 0;  
48.	}  

例题2 HDU 2588 GCD

题目描述
The greatest common divisor GCD(a,b) of two positive integers a and b,sometimes written (a,b),is the largest divisor common to a and b,For example,(1,2)=1,(12,18)=6.
(a,b) can be easily found by the Euclidean algorithm. Now Carp is considering a little more difficult problem:
Given integers N and M, how many integer X satisfies 1<=X<=N and (X,N)>=M.
输入格式
The first line of input is an integer T(T<=100) representing the number of test cases. The following T lines each contains two numbers N and M (2<=N<=1000000000, 1<=M<=N), representing a test case.
输出格式
For each test case,output the answer on a single line.
输入样例
3
1 1
10 2
10000 72
输出样例
1
6
260

思路:当M为1 时,易知答案为N,当M>1时,可以确定满足条件的数一定时N大于M的约数,如果x不能整除N,则gcd(x,N)=1<M,我们知道N的约数(设为x)和N的最大公约数为x,那是否本题只有N的约数满足条件呢?显然不是,数xk(k为满足条件的某些数)与N的约数同样为x,倒退一下,当gcd(N,xk)=x时,有gcd(N/x,k)=1,即k满足与N/x互质时满足N与x*k的最大公约数为x,于是本题就变成了就1-N/x内,与N/x互质的数的个数,用欧拉函数求即可

代码

1.	#include<bits/stdc++.h>  
2.	using namespace std;  
3.	typedef long long ll;  
4.	const int N=1e5;  
5.	ll eular(ll x)  
6.	{  
7.	    ll ans=x;  
8.	    for(int i=2;i*i<=x;i++)  
9.	    {  
10.	        if(x%i==0)  
11.	        {  
12.	            ans=ans-ans/i;  
13.	        }  
14.	        while(x%i==0)  
15.	        {  
16.	            x/=i;  
17.	        }  
18.	    }  
19.	    if(x>1) ans=ans-ans/x;  
20.	    return ans;  
21.	}  
22.	int main()  
23.	{  
24.	    int t;  
25.	    cin>>t;  
26.	    while(t--)  
27.	    {  
28.	        ll ans=0;  
29.	        ll n,m;  
30.	        cin>>n>>m;  
31.	        int i;  
32.	        for(i=1;i*i<n;i++)  
33.	        {  
34.	            if(n%i==0)  
35.	            {  
36.	                if(i>=m)  
37.	                {  
38.	                    ans+=eular(n/i);  
39.	                }  
40.	                if(n/i>=m)  
41.	                {  
42.	                    ans+=eular(i);  
43.	                }  
44.	            }  
45.	        }  
46.	        if(i*i==n&&i>=m) ans+=eular(i);  
47.	        cout<<ans<<endl;  
48.	    }  
49.	    return 0;  
50.	}  

例题3 HDU phi

题目描述
给出若干个正整数n,请你求出最小的m,使得φ(m)≥n。
输入格式
本题有多组输入。
第一行一个正整数T表示数据组数
接下来T行每行一个正整数n
数据保证1≤T≤104,1≤n≤106。
输出格式
共T行,每行一个数代表对应的答案
输入样例
5
1
2
3
4
5
输出样例
1
3
5
5
7

代码

1.	#include<bits/stdc++.h>  
2.	using namespace std;  
3.	typedef long long ll;  
4.	const ll N=5e6+10;  
5.	int phi[N-5];  
6.	bool vis[N-5];  
7.	int prime[N-5];  
8.	struct node  
9.	{  
10.	    int pos;  
11.	    int val;  
12.	    friend bool operator < (const node x,const node y)//对输入进行处理,优先处理n小的输入并记录  
13.	    {  
14.	        return x.val<y.val;  
15.	    }  
16.	}node[10005];  
17.	int ans[10005];  
18.	int t;  
19.	void euler()  
20.	{  
21.	    int now=1;  
22.	    memset(vis,false,sizeof(vis));  
23.	    memset(phi,0,sizeof(phi));  
24.	    vis[1]=true;  
25.	    phi[1]=1;  
26.	    int cnt=0;  
27.	    for(int i=1;i<=N-10;i++)  
28.	    {  
29.	        if(!vis[i])  
30.	        {  
31.	            prime[++cnt]=i;  
32.	            phi[i]=i-1;  
33.	        }  
34.	        for(int j=1;j<=cnt&&prime[j]*i<=N-10;j++)  
35.	        {  
36.	            vis[prime[j]*i]=true;  
37.	            if(i%prime[j]==0)  
38.	            {  
39.	                phi[i*prime[j]]=phi[i]*prime[j];  
40.	                break;  
41.	            }  
42.	            phi[i*prime[j]]=phi[i]*phi[prime[j]-1];  
43.	        }  
44.	        while(phi[i]>=node[now].val&now<=t)  
45.	        {  
46.	            ans[node[now].pos]=i;  
47.	            now++;  
48.	        }  
49.	        if(now>t) return ;  
50.	    }  
51.	}  
52.	int main()  
53.	{  
54.	    euler();  
55.	    cin>>t;  
56.	    for(int i=1;i<=t;i++)  
57.	    {  
58.	        cin>>node[i].val;  
59.	        node[i].pos=i;  
60.	    }  
61.	    sort(node+1,node+t+1);  
62.	    euler();  
63.	    for(int i=1;i<=t;i++)  
64.	        cout<<ans[i]<<endl;  
65.	    return 0;  
66.	}  
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值