欧拉函数原理及练习

问题引入

现在有一个问题,给定一个数n,求出1~n和n互质的数的个数

  • 暴力做法,for一遍,求每一个数和n的GCD,如果结果为1,即为合法答案。这种做法应该说在n比较小的时候还是可以的,如果n比较大,还不够好

欧拉函数原理

  • 欧拉函数可以解决这个问题,设f为欧拉函数,f(x)的含义就是1~x与x互质的元素个数
  • 首先要知道欧拉函数是一个积性函数,什么是积性函数?顾名思义就是形如
    f ( x y ) = f ( x ) × f ( y ) f(xy)=f(x)\times f(y) f(xy)=f(x)×f(y)这样的就叫做积性函数,如何证明?我暂时不想看,等数论书到了再补充吧,暂时知道这是个积性函数就行,也没影响
  • 那么算术基本定理是我们都知道的,就是大于一的数总可以写成
    p 1 e 1 × p 2 e 2 . . . . . . p k e k p_1^{e_1}\times p_2^{e_2}......p_k^{e_k} p1e1×p2e2......pkek的形式,其中p是质数,那么
    f ( p 1 e 1 × p 2 e 2 . . . . . . p k e k ) = f ( p 1 e 1 ) × . . . × f ( p k e k ) f(p_1^{e_1}\times p_2^{e_2}......p_k^{e_k})=f(p_1^{e_1})\times ...\times f(p_k^{e_k}) f(p1e1×p2e2......pkek)=f(p1e1)×...×f(pkek)
    考虑p1的e1次方这个数,小于它的正整数有多少数和它互质呢?考虑有多少不互质的,显然所有p1的倍数的数都是这样的(相等不算),那么有多少个这样的数呢?具体如下
    p 1 、 2 p 1 . . . p 1 e 1 − 1 p_1、2p_1...p_1^{e_1-1} p12p1...p1e11
    因为
    p 1 e 1 = p 1 × p 1 e 1 − 1 p_1^{e_1}=p_1\times p_1^{e_1-1} p1e1=p1×p1e11
    所以上面一共有p1^(e1 - 1)个数,这样
    f ( p 1 e 1 ) × . . . × f ( p k e k ) = p 1 e 1 − 1 × . . . × p k e k − 1 f(p_1^{e_1})\times ...\times f(p_k^{e_k})=p_1^{e_1-1}\times...\times p_k^{e_k-1} f(p1e1)×...×f(pkek)=p1e11×...×pkek1 = p 1 e 1 × p 2 e 2 × . . . × p k e k × ( 1 − 1 p 1 ) × . . . × ( 1 − 1 p k ) =p_1^{e_1}\times p_2^{e_2}\times ... \times p_k^{e_k}\times (1-\frac{1}{p_1})\times ... \times (1-\frac{1}{p_k}) =p1e1×p2e2×...×pkek×(1p11)×...×(1pk1) = n × ( 1 − 1 p 1 ) × . . . × ( 1 − 1 p k ) =n\times (1-\frac{1}{p_1})\times ... \times (1-\frac{1}{p_k}) =n×(1p11)×...×(1pk1)
    用数学符号表示就是
    e u l e r ( n ) = n × ∏ k = 1 n ( 1 − 1 p k ) euler(n)=n\times \prod_{k=1}^n(1-\frac{1}{p_k}) euler(n)=n×k=1n(1pk1)
    这样就得到了欧拉函数的公式

线性筛求解

  • 另一种求欧拉函数的好方法是线性筛进行预处理,适合给定一个不太大的区间,需要多次求某些数欧拉函数的情况
const int N = 1e7;
int p[N + 5];
bool vis[N + 5];
int phi[N + 5];
void Prime(){
  int tot = 0;
  phi[1] = 1;
  for(int i=2;i<=N;i++){
    if(!vis[i]) {
      p[tot++] = i;
      phi[i] = i - 1;
    }
    for(int j=0;j<tot&&p[j]*i<=N;j++){
      vis[i * p[j]] = 1;
      if(i % p[j] == 0) {
        phi[i * p[j]] = p[j] * phi[i];// 如果i%p[j]=0, 满足此关系
        break;
      }
      phi[i * p[j]] = phi[i] * (p[j] - 1);// 如果i%p[j]不为0, 满足积性性质
    }
  }
}
  • 全文背诵吧。。。别证明了

练习

模板题

  • 说多了,上道题试一试,这就是所谓的水题,用来学习算法再合适不过
  • 思路就是唯一分解定理分解n,然后求欧拉函数
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 1e6 + 100;
const double eps = 1e-6;
int Data[MAXN];
ll euler(ll n){
    ll ans = n;
    for(int i=2;i*i<=n;i++){
        if(n % i == 0){
            ans = ans / i * (i - 1);
            while(n % i == 0) n /= i;
        }
    }
    if(n > 1) ans = ans / n * (n - 1);
    return ans;
}
int main(){
    ll n;
    while(cin >> n && n){
        cout << euler(n) << "\n";
    }
    return 0;
}

题目链接
然后看一下这道题,题目意思很好理解

  • 首先当n为1的时候,答案为0
  • 当n为2时候,答案为3
  • n大于2的时候,很容易发现横纵坐标互质时候是能看见的,因为如果不互质,那就说明它处于一条直线的后面位置,前面肯定被挡住了,所以分成两半来求解,分别求欧拉函数即可,特殊情况注意一下
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 1e6 + 100;
const double eps = 1e-6;
int Data[MAXN];
int euler(int n){
    int ans = n;
    for(int i=2;i*i<=n;i++){
        if(n % i == 0){
            ans = ans / i * (i - 1);
            while(n % i == 0) n /= i;
        }
    }
    if(n > 1) ans = ans / n * (n - 1);
    return ans;
}
int main(){
    int n;
    int ans = 3;
    cin >> n;
    if(n == 1) cout << 0;
    else if(n == 2) cout << 3;
    else{
        for(int i=2;i<n;i++){
            ans += 2 * euler(i);
        }
        cout << ans;
    }
    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Clarence Liu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值