欧拉相关

欧拉相关

欧拉函数

欧拉函数 \(\varphi(n)\) 表示 \(1 \sim n\) 内与 \(n\) 互质的数的个数。

性质

  • 欧拉函数是积性函数,特别的有 \(\varphi(2n) = \varphi(n)\)
  • \(\sum_{d | n} \varphi(d) = n\)
    • 证明:设 \(f(x)\) 表示 \(\gcd(k, n) = x (k \in [1, n])\) 的个数,则 \(n = \sum_{d | n} f(d) = \sum_{d | n} \varphi(\dfrac{n}{d}) = \sum_{d | n} \varphi(d)\)
  • \(n\) 为质数时, \(\varphi(n) = n - 1\)
  • \(n = p^k (p \in prime)\) ,则 \(\varphi(n) = p^k - p^{k - 1}\)
  • 由唯一分解定理,设 \(n = \prod p_i^{k_i}\) ,则 \(\varphi(n) = n \times \prod \dfrac{p_i - 1}{p_i}\) ,证明考虑用积性函数性质即可。
  • $n > 2 \rightarrow 2 | \varphi(n) $ ,证明考虑对称性即可。
  • 对于 \(m, n \not = 0\) ,有 \(\varphi(mn) \varphi(\gcd(m, n)) = \varphi(m) \varphi(n) \gcd(m, n)\)

求法

单个数

inline int euler_phi(int n) {
	int phi = n;
	
	for (int i = 2; i * i <= n; ++i)
		if (!(n % i)) {
			phi = phi / i * (i - 1);
			
			while (!(n % i))
				n /= i;
		}
	
	if (n > 1)
		phi = phi / n * (n - 1);
	
	return phi;
}

线性筛

inline void prework(int n) {
	memset(isp, true, sizeof(isp));
	isp[1] = false, phi[1] = 1;
	
	for (int i = 2; i <= n; ++i) {
		if (isp[i])
			pri[++pcnt] = i, phi[i] = i - 1;
		
		for (int j = 1; j <= pcnt && i * pri[j] <= n; ++j) {
			isp[i * pri[j]] = false;
			
			if (i % pri[j])
				phi[i * pri[j]] = phi[pri[j]] * phi[i];
			else {
				phi[i * pri[j]] = pri[j] * phi[i];
				break;
			}
		}
	}
}

杜教筛

namespace Phi {
map<int, ll> mp;

ll f[N], sum[N];

inline void prework() {
	for (int i = 1; i < N; ++i)
		sum[i] = sum[i - 1] + f[i];
}

ll Sum(ll n) {
	if (n < N)
		return sum[n];
	
	if (mp.find(n) != mp.end())
		return mp[n];
	
	ll res = 1ll * n * (n + 1) / 2;
	
	for (ll l = 2, r; l <= n; l = r + 1) {
		r = n / (n / l);
		res -= 1ll * (r - l + 1) * Sum(n / l);
	}
	
	return mp[n] = res;
}
} // namespace Phi

费马小定理

\(p\) 为质数且 \(\gcd(a, p) = 1\) ,则 \(a^{p - 1} \equiv 1 \pmod{p}\)

另一种形式:对于任意整数 \(a\) ,有 \(a^p \equiv a \pmod{p}\)

证明:考虑数学归纳法,显然 \(1^p \equiv 1 \pmod{p}\) 成立。假设 \(a^p \equiv a \pmod{p}\) 成立,则:

\[(a + 1)^p = a^p + \dbinom{p}{1} a^{p - 1} + \cdots + \dbinom{p}{p - 1} a + 1 \equiv a^p + 1 \equiv a + 1 \pmod{p} \]

欧拉定理

欧拉定理:若 \(gcd(a, m) = 1\) ,则 \(a^{\varphi(m)} \equiv 1 \pmod{m}\)

实际上费马小定理就是欧拉定理 \(m\) 为质数的特殊情况。

扩展欧拉定理

\[a^b \equiv \begin{cases} a^{b \bmod \varphi(m)}, &\gcd(a, m) = 1, \\ a^b, &\gcd(a, m) \neq 1, b < \varphi(m), \\ a^{(b \bmod \varphi(m)) + \varphi(m)}, &\gcd(a, m) \neq 1, b \geq \varphi(m). \end{cases} \pmod{m} \]

注:第二行意思是若 \(b < \varphi(m)\) 就不能降幂了。

欧拉反演

本质就是利用 \(n = \sum_{d | n} \varphi(d)\) 做一些变换。

如:

\[\gcd(i, j) = \sum_{d | \gcd(i, j)} \varphi(d) = \sum_{d | i} \sum_{d | j} \varphi(d) \]

于是可以得到:

\[\sum_{i = 1}^n \gcd(i, n) = \sum_{i = 1}^n \sum_{d | n} \sum_{d | i} \varphi(d) = \sum_{d | n} \lfloor \dfrac{n}{d} \rfloor \varphi(d) \]

应用

GCDMAT - GCD OF MATRIX

给定 \(n, m\)\(T\) 次询问,每次给出 \(i_1, j_1, i_2, j_2\) ,求:

\[\sum_{i = i_1}^{i_2} \sum_{j = j_1}^{j_2} \gcd(i, j) \pmod{10^9 + 7} \]

\(n, m \leq 5 \times 10^4\)

容斥完转化为求:

\[\begin{align} S(n, m) &= \sum_{i = 1}^n \sum_{j = 1}^m \gcd(i, j) \\ &= \sum_{i = 1}^n \sum_{j = 1}^m \sum_{d | i} \sum_{d | j} \varphi(d) \\ &= \sum_{d = 1}^n \varphi(d) \sum_{i = 1}^n \sum_{j = 1}^m [d | i] [d | j] \\ &= \sum_{d = 1}^n \varphi(d) \lfloor \dfrac{n}{d} \rfloor \lfloor \dfrac{m}{d} \rfloor \end{align} \]

数论分块可以做到 \(O(n) - O(\sqrt{n})\)

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int Mod = 1e9 + 7;
const int N = 5e4 + 7;

int pri[N], phi[N], sum[N];
bool isp[N];

int T, n, m, pcnt;

inline int add(int x, int y) {
	x += y;
	
	if (x >= Mod)
		x -= Mod;
	
	return x;
}

inline int dec(int x, int y) {
	x -= y;
	
	if (x < 0)
		x += Mod;
	
	return x;
}

inline void sieve() {
	memset(isp, true, sizeof(isp));
    isp[1] = false, phi[1] = 1;

    for (int i = 2; i < N; ++i) {
        if (isp[i])
            pri[++pcnt] = i, phi[i] = i - 1;

        for (int j = 1; j <= pcnt && i * pri[j] < N; ++j) {
            isp[pri[j] * i] = false;

            if (i % pri[j])
                phi[i * pri[j]] = phi[i] * phi[pri[j]];
            else {
            	phi[i * pri[j]] = phi[i] * pri[j];
            	break;
            }
        }
    }

    for (int i = 1; i < N; ++i)
        sum[i] = add(sum[i - 1], phi[i]);
}

inline int S(int n, int m) {
	if (n > m)
    	swap(n, m);
    
    int ans = 0;

    for (int l = 1, r = 0; l <= n; l = r + 1) {
    	r = min(n / (n / l), m / (m / l));
    	ans = add(ans, 1ll * (sum[r] - sum[l - 1]) * (n / l) % Mod * (m / l) % Mod);
    }

    return ans;
}

signed main() {
    sieve();
    scanf("%d%d%d", &T, &n, &m);

    while (T--) {
    	int i1, j1, i2, j2;
    	scanf("%d%d%d%d", &i1, &j1, &i2, &j2);
    	printf("%d\n", add(dec(dec(S(i2, j2), S(i1 - 1, j2)), S(i2, j1 - 1)), S(i1 - 1, j1 - 1)));
    }

    return 0;
}
posted @ 2024-08-12 08:54  我是浣辰啦  阅读(12)  评论(0编辑  收藏  举报