数论 Number Theory

常见数论函数

欧拉函数 φ(x):积性,表示不超过 x 且与 x 互质的数的个数。

单位函数 ε(x):完全积性,定义 ε(x)=[x=1]

恒等函数 idk(x):完全积性,定义 idk(x)=xk,当 k=1 时也叫做标号函数,可写为 id(x)=x

常数函数 1(x):完全积性,定义 1(x)=1

除数函数 σk(x):定义 σk(x)=d|ndk,当 k=0 时可写作 d(x),称为因数个数函数;当 k=1 时可写作 σ(x),称为因数和函数。

莫比乌斯函数 μ(x):积性,定义 μ(x)={1,            x=10,             d>1,d2|n(1)ω(x),otherwise.,其中 ω(x) 表示 x 的不同质因子个数,ω(x) 是一个加性函数。

数论中的加性函数指:对于一个数论函数 f,当整数 ab 时若满足 f(ab)=f(a)+f(b),则 f 为加性函数。

Dirichlet 卷积

对于两个数论函数 fg,定义 fg 的狄利克雷卷积为:

h(x)=d|xf(d)g(xd)=ab=xf(a)g(b)

记为 h=fg

狄利克雷卷积运算满足交换律、结合律与加法结合律(即 (f+g)h=fh+gh)。

等式的性质:f=g 的充要条件是 fh=gh,且 h(1)0

狄利克雷卷积单位元 ε:对于任何数论函数 f,都有 fε=f

数论函数的逆元:若两数论函数 f,g 满足 fg=ε,则称 fg 的逆元,或称 gf 的逆元。

性质

对于两积性数论函数 fg,其狄利克雷卷积 h=fg 也是积性函数。

常见卷积

ε=μ1

d=11

σ=id1

φ=μid

此类卷积会在后面的莫比乌斯反演中大量运用。

Dirichlet 前缀和

对于一个数列 {ai},其狄利克雷前缀和 {bi} 定义为 bk=i|kai

若要求一个数列的 Dirichlet 前缀和,只需先用线性筛筛出下标范围内的所有质数,再枚举质数的倍数求和即可,时间复杂度与埃氏筛相同,即 O(nloglogn)

void Linear_Sieve() {
for (int i = 2; i <= n; i++) {
if (!vis[i]) {
prime[++tot] = i;
}
for (int j = 1; j <= tot && i * prime[j] <= n; j++) {
vis[i * prime[j]] = 1;
if (i % prime[j] == 0) break;
}
}
for (int i = 1; i <= tot; i++) {
for (int j = 1; prime[i] * j <= n; j++) {
a[prime[i] * j] += a[j];
}
}
}

Möbius 反演

若两数论函数 f,g 满足以下关系:

f(n)=d|ng(d)

则称 fgMöbius 变换,gfMöbius 反演。

这里容易看出,f=g1

Möbius 反演的常见形式是 f=ε,g=μ 的情况。

Examples:

P2398 GCD SUM

i=1nj=1ngcd(i,j)

考虑对式子作下列变换:

i=1nj=1ngcd(i,j)=k=1ni=1nj=1n[gcd(i,j)=k]=k=1ni=1nkj=1nk[gcd(i,j)=1]=k=1ni=1nkj=1nkd|gcd(i,j)μ(d)=k=1ni=1nkj=1nkd=1nkμ(d)[d|i][d|j]=k=1nd=1nkμ(d)i=1nk[d|i]j=1nk[d|j]=k=1nd=1nkμ(d)nkdnkd

第一行,枚举 gcd(i,j) 的所有可能取值。

第二行,将 k 提出来。

第三行,观察到 ε(gcd(i,j))=[gcd(i,j)=1],那么运用 Möbius 反演得到 [gcd(i,j)=1]=ε(gcd(i,j))=d|gcd(i,j)μ(d)

第四行,再次枚举 gcd(i,j),观察到若 d|gcd(i,j) 则必然有 d|id|j

第五行,改变枚举顺序。

第六行,观察到 [1,nk] 范围内 d 的倍数只有 nkd 个。

//上面的过程好像有问题,懒得改了。

最后,线性筛出 μ 的值,整除分块即可,时间复杂度 O(nn)

本题还有不用反演的做法:利用 φ 的性质,这里不赘述,时间复杂度也为 O(nn)

下面是 Möbius 反演板子题:

P2257 YY 的 GCD

i=1nj=1m[gcd(i,j)=p],pprime

比刚刚那题一目了然,但刚刚用 φO(Tnn) 的做法无法通过,只能用反演做法。

化简得到:

p=1min(n,m)d=1min(np,mp)μ(d)npdmpd,pprime

此时不能再枚举 p,因为枚举 p 的时间复杂度还是 O(Tnn) 的。

考虑设 C=pd,pprime,再枚举 C,则原式化为:

C=1min(n,m)nCmCp|C,pprimeμ(Cp)

预处理后一部分,整除分块即可,时间复杂度 O(n+Tn)

//Made By Cuset. 喵喵~
#include <bits/stdc++.h>
#include <bits/extc++.h>
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int MAXN = 1e7 + 5;
ll mu[MAXN], prime[MAXN], f[MAXN], tot, fsum[MAXN], n, m, t;
bool vis[MAXN];
void Linear_Sieve() {
mu[1] = 1;
for (int i = 2; i <= MAXN - 5; i++) {
if (!vis[i]) {
prime[++tot] = i;
mu[i] = -1;
}
for (int j = 1; j <= tot && i * prime[j] <= MAXN - 5; j++) {
vis[i * prime[j]] = 1;
if (i % prime[j] == 0) break;
else mu[i * prime[j]] = -mu[i];
}
}
for (int i = 1; i <= tot; i++) {
for (int j = 1; j * prime[i] <= MAXN - 5; j++) {
f[j * prime[i]] += mu[j];
}
}
for (int i = 1; i <= MAXN - 5; i++) fsum[i] = fsum[i - 1] + f[i];
}
inline ll read() {
ll x = 0;
bool f = true;
char c = getchar();
while (!isdigit(c)) {
if (c == '-') f = false;
c = getchar();
}
while (isdigit(c)) {
x = x * 10 + c - '0';
c = getchar();
}
return f ? x : -x;
}
inline void write(ll x, bool f = 0) {
ll tp2 = 0;
char Nu[64];
if (x<0) x = -x, putchar('-');
if (x==0) putchar('0');
else {
while (x) {
Nu[++tp2] = x % 10 + '0', x /= 10;
}
while (tp2) putchar(Nu[tp2--]);
}
if (f) putchar('\n');
else putchar(' ');
return;
}
int main() {
Linear_Sieve();
cin >> t;
while (t--) {
n = read();
m = read();
ll ans = 0;
if (n > m) swap(n, m);
for (int l = 1, r; l <= n; l = r + 1) {
r = min(n / (n / l), m / (m / l));
ans += (fsum[r] - fsum[l - 1]) * (n / l) * (m / l);
}
write(ans, true);
}
return 0;
}

杜教筛

类比线性筛、埃氏筛能筛质数与积性函数值,杜教筛是一种用于大范围筛数论函数前缀和的工具,它的底层思想是构造卷积与 Möbius 反演的运用。

假设现在需要求 f 的前缀和,记 i=1nf(i)=S(n),那么考虑:

i=1n(fg)(i)=i=1nd|if(d)g(id)=d=1ng(d)S(nd)

推出杜教筛的核心式子:

g(1)S(n)=i=1n(fg)(i)i=2ng(i)S(ni)

理论上,只要找到一个合适的积性函数 g 去计算 gfg 的前缀和,那么便可以计算任一数论函数的前缀和。

代码如下:

ll GetSum(int n) { // 算 f 前缀和的函数
ll ans = ...; // f * g 的前缀和
for(ll l = 2, r; l <= n; l = r + 1) {
r = (n / (n / l));
ans -= (g_sum(r) - g_sum(l - 1)) * GetSum(n / l);
// g_sum 是 g 的前缀和
// 递归 GetSum 求解
} return ans;
}

计算 φ

考虑 φ1=id,那么 f=φ,g=1,那么 fg 的前缀和即 id 的前缀和就是 n(n+1)2

计算 μ

考虑 μ1=ε,那么 f=μ,g=1,那么 fg 的前缀和即 ε 的前缀和就是 1

朴素的杜教筛的时间复杂度是 O(n34)。可以先用线性筛筛出 m 个前缀和并用 unordered_map 存下来,当 m=n23 时杜教筛时间复杂度取最小值,为 O(n23)

原根与离散对数

满足 an1(modm)n 称为 am 的阶,记作 δm(a)

性质 1

a,a2,,aδm(a)m 两两互不同余。

证明 1

若存在 1i<j<δm(a),使得aiaj(modm),则 a|ij|1(modm),显然 0<|ij|<δm(a),与阶的最小性相矛盾,故原命题成立。

性质 2

an1(modm),则 δm(a) | n

证明 2

n=δm(a)q+r,0r<δm(a)

r0,则

arar(aδm(a))qan1(modm)

与阶的最小性相矛盾。

r=0,则 δm(a) | n,故原命题成立。

据此还能推出:若 apaq(modm),则 pq(modm)δm(a) | φ(m)

求阶

由于 δm(a) | φ(m),所以求阶只需要尝试把所有 φ(m) 的所有因子除去便能求出 δm(a),这就是试除法。

试除法的步骤是:

  1. d=φ(m)px,其中 px 表示已除去的所有因子的积。

  2. 在试除的过程中,若 ad1(modm) 不成立,则该因子不能除去,否则可以除去。

原根

mN,gZ,若 mg,δm(g)=φ(m),则称 g 为模 m 的一个原根。

原根判定定理

m3,mg,则 g 是模 m 的一个原根的充要条件是:对于 m 的每个素因子 p,都有 gφ(m)p/  1(modm)

证明见 OI-wiki

原根个数

m 存在原根,则原根个数为 φ(φ(m))

原根存在性定理

一个数 m 存在原根当且仅当 m=2,4,pα,p2α;p 是奇素数,αN

离散对数

离散对数的定义与对数类似。

m 有原根,它的一个原根为 g。对一个 a 使 am,必定存在唯一的 k(0k<φ(m)),使得 gka(modm),则称 k 为以 g 为底,模 m 的离散对数,记作 k=indga

本文作者:Cuset_VoidAldehyde

本文链接:https://www.cnblogs.com/CusetVoidAldehyde/p/18286073

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Cuset_VoidAldehyde  阅读(27)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起