acwing算法基础之数学知识--筛法求1~n中每个数的欧拉函数

目录

  • 1 基础知识
  • 2 模板
  • 3 工程化

1 基础知识

已知数i、质数a和数i的欧拉函数值 ϕ ( i ) \phi(i) ϕ(i),求数i*a的欧拉函数值 ϕ ( i ⋅ a ) \phi(i\cdot a) ϕ(ia)

  1. 如果质数a是数i的质因子(即a % i == 0),那么有 ϕ ( a ⋅ i ) = a ⋅ ϕ ( i ) \phi(a\cdot i)=a\cdot \phi(i) ϕ(ai)=aϕ(i)。证明如下,
    ϕ ( a ⋅ i ) = a ⋅ i ⋅ Σ j ( 1 − 1 p j ) = a ⋅ ϕ ( i ) \phi(a\cdot i)=a\cdot i \cdot \Sigma_{j}(1-\frac{1}{p_j})=a\cdot \phi(i) ϕ(ai)=aiΣj(1pj1)=aϕ(i)
    注意 p j p_j pj中包含了a。
  2. 如果质数a不是数i的质因子(即a % i != 0),那么有 ϕ ( a ⋅ i ) = ( a − 1 ) ⋅ ϕ ( i ) \phi(a\cdot i)=(a - 1) \cdot \phi(i) ϕ(ai)=(a1)ϕ(i)。证明如下,
    ϕ ( a ⋅ i ) = a ⋅ i ⋅ Σ j ( 1 − 1 p j ) ⋅ ( 1 − 1 a ) = a ⋅ ϕ ( i ) ⋅ ( 1 − 1 a ) = ( a − 1 ) ⋅ ϕ ( i ) \phi(a\cdot i)=a \cdot i \cdot \Sigma_j(1-\frac{1}{p_j}) \cdot (1-\frac{1}{a})=a\cdot \phi(i) \cdot (1-\frac{1}{a})=(a-1)\cdot \phi(i) ϕ(ai)=aiΣj(1pj1)(1a1)=aϕ(i)(1a1)=(a1)ϕ(i)
    注意 p j p_j pj中并没有包含a(因为a不是i的质因子)。

质数的欧拉函数值等于它本身减1。

故可以在线性筛法求1~n的质数中,计算每个数的欧拉函数值,代码如下,

int st[N];
int primes[N];
int phi[N];
int cnt;

void get_phis(int n) {
	phi[1] = 1;
	for (int i = 2; i <= n; ++i) {
		if (!st[i]) {
			primes[cnt++] = i;
			phi[i] = i - 1;
		}
		for (int j = 0; primes[j] <= n / i; ++j) {
			st[i * primes[j]] = true;
			if (i % primes[j] == 0) {
				phi[i * primes[j]] = primes[j] * phi[i];
				break;
			}
			phi[i * primes[j]] = (primes[j] - 1) * phi[i];
		}
	}
	//phi[i]即为i的欧拉函数值
}

欧拉定理:若a与b互质(即a和b的最大公约数为1),那么有 a ϕ ( b ) % b = = 1 a^{\phi(b)} \% b == 1 aϕ(b)%b==1

费马定理:若a与b互质且b是质数,那么有 a b − 1 % b = = 1 a^{b-1}\% b==1 ab1%b==1

2 模板

int primes[N], cnt;     // primes[]存储所有素数
int euler[N];           // 存储每个数的欧拉函数
bool st[N];         // st[x]存储x是否被筛掉


void get_eulers(int n)
{
    euler[1] = 1;
    for (int i = 2; i <= n; i ++ )
    {
        if (!st[i])
        {
            primes[cnt ++ ] = i;
            euler[i] = i - 1;
        }
        for (int j = 0; primes[j] <= n / i; j ++ )
        {
            int t = primes[j] * i;
            st[t] = true;
            if (i % primes[j] == 0)
            {
                euler[t] = euler[i] * primes[j];
                break;
            }
            euler[t] = euler[i] * (primes[j] - 1);
        }
    }
}

3 工程化

题目1:计算1~n的欧拉函数值的和。

#include 

using namespace std;

const int N = 1e6 + 10;
int n, cnt;
int primes[N];
bool st[N];
int phi[N];

void get_phis() {
    phi[1] = 1;
    for (int i = 2; i <= n; ++i) {
        if (!st[i]) {
            primes[cnt++] = i;
            phi[i] = i - 1;
        }
        for (int j = 0; primes[j] <= n / i; ++j) {
            st[i * primes[j]] = true;
            if (i % primes[j] == 0) {
                phi[i * primes[j]] = primes[j] * phi[i];
                break;
            }
            phi[i * primes[j]] = (primes[j] - 1) * phi[i];
        }
    }
    
    long long res = 0;
    for (int i = 1; i <= n; ++i) {
        res += phi[i];
    }
    
    cout << res << endl;
    return;
}

int main() {
    cin >> n;
    
    get_phis();
    
    return 0;
}

你可能感兴趣的:(Acwing,C++学习,算法)