欧拉函数
概述
欧拉函数就是对于一个正整数\(n\) ,小于\(n\) 且和\(n\) 互质的正整数(包括1)的个数,记作\(φ(n)\) 。
欧拉函数的通式:
\(φ(n)=n*(1-1/p1)(1-1/p2)(1-1/p3)*(1-1/p4)……(1-1/pn)\)
其中\(p_1, p_2,...,p_n\) 为\(n\) 的所有质因数,\(n\) 是不为\(0\) 的整数。\(φ(1)=1\) (唯一和1互质的数就是1本身)。
性质
当\(m,n\) 互质时,有\(\phi(m \times n)= \phi(m)* \phi(n)\) ;
若\(i%p==0\) ,有\(\phi(i \times p) = p \times \phi(i)\) ;
对于互质\(x\) 与\(p\) ,有\(x^{\phi(p)}≡1(mod \ p)\) ,因此x的逆元为\(x^{\phi(p)-1}\) ,即欧拉定理。
(特别地,当p为质数时,\(\phi(p)=p-1\) ,此时逆元为\(x^{p-2}\) ,即费马小定理)
当\(n\) 为奇数时,\(\phi(2n)=\phi(n)\)
若\(x\) 与\(p\) 互质,则\(p-x\) 也与\(p\) 互质,因此小于\(p\) 且与\(p\) 互质的数之和为\(\phi(x) \times x/2\) ;
\(N>1\) ,不大于\(N\) 且和\(N\) 互素的所有正整数的和是 \(1/2 \times N \times eular(N)\) 。
欧拉筛模板
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 void eular_ () //欧拉筛模板
{
memset ( vis , true , sizeof ( vis ));
int cnt = 1 ;
vis [ 1 ] = false ;
for ( int i = 2 ; i <= N -5 ; i ++ )
{
if ( vis [ i ]) prime [ cnt ++ ] = I ;
for ( int j = 1 ; j < cnt && prime [ j ] * i <= N -5 ; j ++ )
{
vis [ prime [ j ] * i ] = false ;
if ( i % prime [ j ] == 0 )
{
break ;
}
//若i为p[j]的倍数,则i=k*p[j],
//在和p[j+1]相乘后得出的x=i*p[j+1]=p[j]*k*p[j+1]
//则在i=k*p[j+1]时,由于j从小到大,必定经过之前的p[j],会重复计算
}
}
}
欧拉函数模板
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 int euler ( int x )
{
int ans = x ;
for ( int i = 2 ; i * i <= x ; i ++ ) //模拟(1-p1)*(1-p2)……过程,pi为x的质因数
{
if ( x % i == 0 )
{
ans = ans - ans / i ;
}
while ( x % i == 0 )
{
x /= i ;
}
}
if ( x > 1 ) ans = ans - ans / x ; //若x不为1,说明仍有一个质因数没有乘
return ans ;
}
线性求欧拉函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 void euler_ ()
{
memset ( vis , true , sizeof ( vis ));
memset ( phi , 0 , sizeof ( phi ));
int cnt = 1 ;
vis [ 1 ] = false ;
phi [ 1 ] = 1 ; //特判1,gcd(1,1)=1
for ( int i = 2 ; i <= N -5 ; i ++ )
{
if ( vis [ i ])
{
prime [ cnt ++ ] = i ;
phi [ i ] = i -1 ;
}
for ( int j = 1 ; j < cnt && prime [ j ] * i <= N -5 ; j ++ )
{
vis [ prime [ j ] * i ] = false ;
if ( i % prime [ j ] == 0 )
{
phi [ prime [ j ] * i ] = phi [ i ] * prime [ j ];
break ;
}
phi [ prime [ j ] * i ] = phi [ i ] * phi [ prime [ j ]];
//若i为p[j]的倍数,则i=k*p[j],
//在和p[j+1]相乘后得出的x=i*p[j+1]=p[j]*k*p[j+1]
//则在i=k*p[j+1]时,由于j从小到大,必定经过之前的p[j],会重复计算
}
}
}
例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)
输入样例
输出样例
题解
线性求欧拉函数模板题
代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 #include <bits/stdc++.h>
using namespace std ;
typedef long long ll ;
const int N = 3e6 + 10 ;
int phi [ N ];
bool vis [ N ];
int prime [ N ];
int sum [ N ];
void eular_ () //欧拉筛模板
{
memset ( vis , true , sizeof ( vis ));
memset ( phi , 0 , sizeof ( phi ));
int cnt = 1 ;
vis [ 1 ] = false ;
phi [ 1 ] = 1 ; //特判1,gcd(1,1)=1
for ( int i = 2 ; i <= N -5 ; i ++ )
{
if ( vis [ i ])
{
prime [ cnt ++ ] = i ;
phi [ i ] = i -1 ;
}
for ( int j = 1 ; j < cnt && prime [ j ] * i <= N -5 ; j ++ )
{
vis [ prime [ j ] * i ] = false ;
if ( i % prime [ j ] == 0 )
{
phi [ prime [ j ] * i ] = phi [ i ] * prime [ j ];
break ;
}
phi [ prime [ j ] * i ] = phi [ i ] * phi [ prime [ j ]];
//若i为p[j]的倍数,则i=k*p[j],在和p[j+1]相乘后得出的*p[j+1]=p[j]*k*p[j+1]
//则在i=k*p[j+1]时,由于j从小到大,必定经过之前的p[j],会重复计
}
}
}
int main ()
{
int a , b ;
eular_ ();
while ( cin >> a >> b )
{
ll ans = 0 ;
for ( int i = a ; i <= b ; i ++ ) ans += phi [ i ];
cout << ans << endl ;
}
return 0 ;
}
例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.
输入样例
输出样例
题解
当\(M\) 为\(1\) 时,易知答案为\(N\) ,当\(M>1\) 时,可以确定满足条件的数一定时\(N\) 大于\(M\) 的约数,如果\(x\) 不能整除\(N\) ,则\(gcd(x,N)=1<M\) ,我们知道\(N\) 的约数(设为\(x\) )和\(N\) 的最大公约数为\(x\) ,那是否本题只有N的约数满足条件呢?显然不是,数\(x*k\) (\(k\) 为满足条件的某些数)与\(N\) 的约数同样为\(x\) ,倒推一下,当\(gcd(N,x \times k)=x\) 时,有\(gcd(N/x,k)=1\) ,即\(k\) 满足与\(N/x\) 互质时满足\(N\) 与\(x \times k\) 的最大公约数为\(x\) ,于是本题就变成了就\(1-N/x\) 内,与\(N/x\) 互质的数的个数,用欧拉函数求即可
代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 #include <bits/stdc++.h>
using namespace std ;
typedef long long ll ;
const int N = 1e5 ;
ll eular ( ll x )
{
ll ans = x ;
for ( int i = 2 ; i * i <= x ; i ++ )
{
if ( x % i == 0 )
{
ans = ans - ans / i ;
}
while ( x % i == 0 )
{
x /= i ;
}
}
if ( x > 1 ) ans = ans - ans / x ;
return ans ;
}
int main ()
{
int t ;
cin >> t ;
while ( t -- )
{
ll ans = 0 ;
ll n , m ;
cin >> n >> m ;
int i ;
for ( i = 1 ; i * i < n ; i ++ )
{
if ( n % i == 0 )
{
if ( i >= m )
{
ans += eular ( n / i );
}
if ( n / i >= m )
{
ans += eular ( i );
}
}
}
if ( i * i == n && i >= m ) ans += eular ( i );
cout << ans << endl ;
}
return 0 ;
}
例3.HDU phi
题目描述
给出若干个正整数n,请你求出最小的m,使得φ(m)≥n。
输入格式
本题有多组输入。
第一行一个正整数T表示数据组数
接下来T行每行一个正整数n
数据保证\(1≤T≤104,1≤n≤106\) 。
输出格式
共T行,每行一个数代表对应的答案
输入样例
输出样例
代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66 #include <bits/stdc++.h>
using namespace std ;
typedef long long ll ;
const ll N = 5e6 + 10 ;
int phi [ N -5 ];
bool vis [ N -5 ];
int prime [ N -5 ];
struct node
{
int pos ;
int val ;
friend bool operator < ( const node x , const node y ) //对输入进行处优先处理n小的输入并记录
{
return x . val < y . val ;
}
} node [ 10005 ];
int ans [ 10005 ];
int t ;
void euler ()
{
int now = 1 ;
memset ( vis , false , sizeof ( vis ));
memset ( phi , 0 , sizeof ( phi ));
vis [ 1 ] = true ;
phi [ 1 ] = 1 ;
int cnt = 0 ;
for ( int i = 1 ; i <= N -10 ; i ++ )
{
if ( ! vis [ i ])
{
prime [ ++ cnt ] = i ;
phi [ i ] = i -1 ;
}
for ( int j = 1 ; j <= cnt && prime [ j ] * i <= N -10 ; j ++ )
{
vis [ prime [ j ] * i ] = true ;
if ( i % prime [ j ] == 0 )
{
phi [ i * prime [ j ]] = phi [ i ] * prime [ j ];
break ;
}
phi [ i * prime [ j ]] = phi [ i ] * phi [ prime [ j ] -1 ];
}
while ( phi [ i ] >= node [ now ]. val & now <= t )
{
ans [ node [ now ]. pos ] = i ;
now ++ ;
}
if ( now > t ) return ;
}
}
int main ()
{
euler ();
cin >> t ;
for ( int i = 1 ; i <= t ; i ++ )
{
cin >> node [ i ]. val ;
node [ i ]. pos = i ;
}
sort ( node + 1 , node + t + 1 );
euler ();
for ( int i = 1 ; i <= t ; i ++ )
cout << ans [ i ] << endl ;
return 0 ;
}