欧拉φ函数


这是我看过某同学写的之后,应为感觉自己要用所以自己摘要了一下下,
哪里写错了的地方,或哪里有意见不一致的地方还请各位路过的帮忙给改改
谢谢帮助.........

φ(n)是所有小于n的正整数里,和n互素的整数的个数。n是一个正整数。
如果n的标准素因子分解式是p1^a1*p2^a2*……*pm*am,其中众pj(j=1,2,……,m)都是素数,而且两两不等。则有
φ(n)=n(1-1/p1)(1-1/p2)……(1-1/pm)

性质
根据Fermat-Euler定理:
对任何两个互质的正整数a, m, m>=2有
a^φ(m)≡1(mod m)

当m是质数p时,此式则为
a^(p-1)≡1(mod m)

若m=m1*m2*m3*......*mk,而m1,m2,m3......mk两两互质,
则φ(m)=φ(m1)*φ(m2)*φ(m3)*φ(m4)......*φ(mk)。

a为质数
若(N % a==0 && (N/a)%a==0) 则有
φ(n) = φ(n/a)*a
若(N % a==0 && (N/a)%a!=0) 则有:
φ(n) = φ(n/a)*(a-1)

代码
不借助质数表

int euler(int n){
int m = n, i;
if(n % 2 == 0) m /= 2;
while(n % 2 == 0) n /= 2;
for(i = 3; n != 1; i += 2){
if(n % i == 0) m -= m / i;
while(n % i == 0) n /= i;
}
return m;
}


借助质数表

const int maxn = 40000;
bool pf[maxn];
int p[maxn], numOfP = 0;
void init(){
memset(pf, 0, sizeof(pf));
for(int i = 2; i < maxn; i++){
if(!pf[i]){
p[numOfP++] = i;
for(int j = i * i; j < maxn; j += i)
pf[j] = true;
}
}
}
int euler1(int n){
int sum = 1;
int tmp;
for(int i = 0; i < numOfP; i++){
if(n == 1) break;
if(n % p[i] == 0){
tmp = 0;
while(n % p[i] == 0){
n /= p[i];
tmp++;
}
for(int j = 1; j < tmp; j++)
sum *= p[i];
sum *= p[i] - 1;
}
}
if(n == 1)
return sum;
else
return sum * (n - 1);
}
int euler2(int n)
{
int i;
for(i = 2; i <= sqrt((double)n); i++){
if(n % i == 0 && !pf[i]){
n /= i;
if(n % i ==0)
return i * euler2(n);
else
return (i - 1) * euler2(n);
}
}
return n-1;
}

扩展欧拉函数
我们求 x1..xn,m这样的序列的个数,其中xi <= m(1<=i<=n), gcd(x1, ..,xn,m)=1;

当 n 为素数时: phi(m,n) = m^n-1
当 n 为合数时: phi(m,n) = m^n∏(1-1/p^n) 其中(p为n的素数因子)