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 ans;
}
int main()
{
ll n,m;
int Tcase;
scanf("%d",&Tcase);
for(int ii = 1; ii <= Tcase ; ii ++)
{
scanf("%I64d%I64d",&n,&m);
double t = sqrt(n);
ll temp = euler(m);
ll ans = 0;
int i;
for(i = 1; i < t; i ++)
{
if(n % i == 0)
{
if(i >= m)
ans += euler(n/i);
if(n / i >= m )
ans += euler(i);
}
}
if(i * i == n && i >= m)
{
ans += euler(i);
}
cout << ans << endl;
}
return 0;
}
The Euler Function
题意:直接的一个求euler,输入一个a,b,求出euler(x)之和,x属于【a,b】;
思路:打表一下;
#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 ans;
//}
int euler[maxn];
void Init()
{
for(int i = 2; i < maxn ; i ++)
euler[i] = 0;
euler[1] = 1;
for(int i = 2; i < maxn ; i ++)
{
if(!euler[i])
for(int j = i ; j < maxn ; j += i)
{
if( ! euler[j])
euler[j] = j;
euler[j] = euler[j] /i *(i - 1);
}
}
}
int main()
{
Init();
int n,m;
while( ~ scanf("%d%d",&n,&m) )
{
ll ans = 0;
for(int i = n ; i <= m ; i ++)
{
ans += euler[i];
}
cout << ans << endl;
}
return 0;
}
找新朋友
题意:新朋友就是小于n,并且与互质的数,求新朋友的个数;
思路:因为x不能取n,所以gcd不能等于1,之后直接euler;
#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 ans;
}
int main()
{
ll n,m;
int Tcase;
scanf("%d",&Tcase);
for(int ii = 1; ii <= Tcase ; ii ++)
{
scanf("%I64d",&n);
double t = sqrt(n);
ll ans = 0;
int i ;
for(i = 1; i < t; i ++)
{
if(n % i == 0)
{
if(i > 1)
ans += euler(n/i);//公因数是i;
if(n / i > 1)
ans += euler(i);//公因数是n /i;
}
}
if(i * i == n && i != 1)
{
ans += euler(i);
}
cout << n - ans << endl;
}
return 0;
}
题意:求满足 gcd(n−a,n)×gcd(n−b,n)=nk
的a,b的数目:其中a,b属于【1,n】;
思路:gcd(0,x) == x,所以gcd(n - a ,n)是可以等于 n的;分析:k == 2的时候,只有a == b == n的时候,才能使得n * n == n ^ 2;
当k > 2的时候,除了n == 1的数都是0,因为前面最多是n ^2;
于是就剩下对k == 1的分析了,即gcd(n−a,n)×gcd(n−b,n)=n;
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mod 1000000000 + 7
ll euler(ll x)
{
int ans = x;
for(int i = 2; i * i <= 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 ans;
}
int main()
{
ll n,k;
while( ~ scanf("%I64d%I64d",&n,&k) )
{
if(n == 1 )
{
cout << 1 << endl;
continue;
}
if(k > 2)
{
cout << 0 << endl;
continue;
}
if(k == 2)
{
cout << 1 << endl;
continue;
}
double t = sqrt(n);
ll ans = 0;
int i;
for(i = 1; i < t ; i ++)
{
if( n % i == 0 )//因为两个因数没有一个是能够达到n
{
ans += euler(i) * euler(n / i) * 2;
ans %= mod;
}
}
if(i * i == n)
{
ans += euler(i) * euler(i);//当两个因数相同的时候;
}
ans %= mod;
cout << ans << endl;
}
return 0;
}
#include<iostream>
#include<cstdio>
#include<cmath>
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 ans;
}
int main()
{
ll n;
while( ~ scanf("%I64d",&n) )
{
ll ans = 0;
int i ;
for(i = 1; i < sqrt(n) ; i ++)
{
if(n % i == 0)
{
ans += i * euler(n/i) + n / i * euler(i);
}
}
if(i * i == n)
{
ans += i * euler(i);
}
cout << ans << endl;
}
return 0;
}
Stern-Brocot Tree
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1000000 + 10;
typedef long long ll;
ll euler[maxn];
ll ans[maxn];
void Init()
{
memset(euler,0,sizeof(euler));
euler[1] = 1;
for(int i = 2 ; i < maxn ; i ++)
{
if( !euler[i])
{
for(int j = i; j < maxn ; j += i)
{
if(!euler[j])
euler[j] = j;
euler[j] = euler[j] / i * (i- 1);
}
}
}
ans[1] = 1;
for(int i = 2; i < maxn ;i ++)
{
ans[i] = ans[i - 1] + euler[i];
}
}
int main()
{
Init();
int n;
while( ~ scanf("%d",&n) )
{
cout << ans[n] * 2 + 1 << endl;
}
return 0;
}