euler函数:对于一个数n,euler(n)的求的是在【1,n】之间与n互质的数的个数,公式为:euler(n) = n * (1 - 1/ p1) * (1 - 1/p2) * (1 - 1/p3) * ......*(1- 1/pn),其中p1,p2,.....pn是n的质因数,不重叠;
实现的算法是
typedef long long ll;
//直接求解欧拉函数
ll euler(ll x){ //返回euler(n)
ll ans = x;
for(ll i = 2;i*i <= x;i ++){
if(x%i == 0){
res = res / i * (i-1);//先进行除法是为了防止中间数据的溢出
while(x % i == 0) x/=i;
}
}
if(x > 1) res = res / x * (x-1);//未除尽就说明x是素数,之后进行算式
return res;
}
//筛选法打欧拉函数表
#define Max 1000001
ll euler[maxn];
void Init(){
euler[1] = 1;
for(ll i = 2;i < maxn;i ++)
euler[i] = i;
for(ll i = 2;i < maxn;i++)
if(euler[i] == i)
for(ll j = i;j < Max;j += i)
euler[j] = euler[j] / i * (i-1);//先进行除法是为了防止中间数据的溢出
}
更快的时候就是用素数表进行euler函数的运算:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 50000 + 10;
bool is_prime[maxn];
int prime[maxn];
int len = 0;
void Init()//先打个50000的素数表
{
memset(is_prime,true,sizeof(is_prime));
is_prime[0] = is_prime[1] = false;
for(int i = 2; i < maxn ; i ++)
{
if(is_prime[i])
{
prime[len ++] = i;
for(int j = i * 2; j < maxn ; j += i)
is_prime[j] = false;
}
}
}
ll euler(ll x)
{
ll ans = x;
for(ll i = 0 ; prime[i] * prime[i] <= x && i < len; i ++)
{
if(x % prime[i])
{
ans = ans /prime[i] * (prime[i] - 1);
while(x % prime[i] == 0)
x /= prime[i];
}
}
if(x > 1)
ans = ans / x * (x - 1);
return ans;
}
int main()//因为公式中的是x的质因数,可以先打一个素数表,之后走素数表就行了
{
Init();
cout << euler(2) << endl;
return 0;
}
以上就是euler函数的实现方法,有打表和直接求;
euler的性质:
先写出两个常用定理:
1.euler定理:对于两个互质的数a,m(m>= 2),有a^(euler(m))
1 (mod m);
2.费马小定理:当m为质数的时候a^(m - 1)
1 (mod m),因为当m为质数的时候,euler(m) = m - 1;
3.如果p是质数,那么euler(p) = p - 1;推广:p是质数,a是一个正整数,那么 euler(p^n)= p^n - p^(n - 1);
4.如果m,n是互质的两个正整数,那么euler(n*m)= euler(n)*euler(m);
5.对于一个数n,euler(n)的求的是在【1,n】之间与n互质的数的个数,公式为:euler(n) = n * (1 - 1/ p1) * (1 - 1/p2) * (1 - 1/p3) * ......*(1- 1/pn),其中p1,p2,.....pn是n的质因数,不重叠;
6.当n为奇数时,有euler(2n)= euler(n);
7.若n是一个大于2的正整数,那么euler(n)是偶数,即euler(n)%2 == 0;
euler的应用:
1.运用euler求gcd;求小于n的数 并且与n的最大公倍数gcd为i的个数 : 假设是gcd(x,n) == i ,(x < n);对于n来说,因数是i,那么说明 n/i 和 x/i互质,对于gcd(x,n) == i,如果i 一定,要 求 x的个数,就相当于求 与n/i互质的数的个数,即 x/i的个数,因为x<=n,要 求的个数就是euler(n/i)的数目;
2.求最简真分数,即 分子小于分母 并且 分子和分母互质的分数的个数 : 就相当于 对于一个固定的分母n,求出比小且与他互质的数的个数,即euler(n);
题意:输入一个n,m,然后要求比n小的数与n的gcd大于m的个数,即gcd(x,n)>= m,其中x 属于【1,n】,求x的个数;
思路:遍历一遍,然后判断因数是不是 大于等于m,是的话就加上;
#include<iostream>
#include<cstdio>
#include<cmath>
const int maxn = 3000000 + 10;
using namespace std;
typedef long long ll;
ll euler(ll x)
{
ll ans = x;
for(int i = 2; i <= sqrt(x) ; i ++)
{
if(x % i == 0)
{
ans = ans / i * (i - 1);
while(x% i == 0)
x /= i;
}
}
if(x > 1)
ans = ans / x * (x - 1);
return a