快速幂 & 欧拉函数

快速幂

code

快速幂模板

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
func qmi(a, b, p int) int {
	res := 1 % p

	for b != 0 {
		// 如果最低位是1的话,乘到答案中
		if b&1 == 1 {
			res = res * a % p
		}
		b >>= 1 // 去掉这位,看下一位
		a = a * a % p // 准备下一位的要乘的数
	}

	return res
}

逆元


欧拉函数

$1~n$ 中,和 n 互质的数的个数。 例如 $\varphi (6) = 2$, 因为只有 1,5 和 6 互质。

算术基本定理,n 可以分解成质因子的乘积

$$ n = p_1^{c_1}p_2^{c_2}p_3^{c_3} ... p_m^{c_m} $$

$$ \varphi (n) = n*(1- \frac{1}{p_1}) * (1- \frac{1}{p_2}) * ... * (1- \frac{1}{p_k}) $$

code

第一种:分解质因数

因为我们要求 n 的 1-n 中的质因子,所以可以在分解质因数时,顺便按照公式进行乘质因子

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
for k := 0; k < n; k++ {
    a := rnI()
    res := a
    for i := 2; i <= a/i; i++ {
        if a%i == 0 {
            res = res * (i - 1) / i
            for a%i == 0 {
                a /= i
            }
        }
    }

    if a > 1 {
        res = res * (a - 1) / a
    }
    fmt.Fprintln(ot, res)
}

第二种:线性筛法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
func euler() int {
	phi[1] = 1 // 1的欧拉函数是1

	for i := 2; i <= n; i++ {
		if !st[i] {
			primes[cnt] = i
			cnt++
			// i 是质数,那么它的欧拉函数是
			phi[i] = i - 1
		}

		for j := 0; i*primes[j] <= n; j++ {
			st[primes[j]*i] = true
			if i%primes[j] == 0 {
				// 情况2 -> i整除pirmes[j] , 说明primes[j] 肯定是i的质数中的质数,
                // 欧拉公式和次数没关系,所以只是系数成了一个primes[j]
				phi[i*primes[j]] = primes[j] * phi[i]
				break
			}
			// 情况3
            // 要乘1个primes[j] ,还要乘以(1-1/primes[j])
			phi[i*primes[j]] = phi[i] * (primes[j] - 1)

		}
	}

	res := 0
	for i := 1; i <= n; i++ {
		res += phi[i]
	}

	return res
}