Martian148's blog Martian148's blog
首页
  • ICPC 算法笔记
  • ICPC 算法题解
  • 体系结构
  • 高等数学
  • 线性代数
  • 概率论与数理统计
  • 具体数学
  • Martian148的奇思妙想
  • 游记
  • 通识课笔记
关于
  • useful 网站
  • 友情链接
  • 分类
  • 归档

Martian148

一只热爱文科的理科生
首页
  • ICPC 算法笔记
  • ICPC 算法题解
  • 体系结构
  • 高等数学
  • 线性代数
  • 概率论与数理统计
  • 具体数学
  • Martian148的奇思妙想
  • 游记
  • 通识课笔记
关于
  • useful 网站
  • 友情链接
  • 分类
  • 归档
  • 线上赛板子(实时更新)
  • 数据结构

  • 数学

    • 数论
      • 素数
        • 素数的判定
        • 欧拉筛
      • 分解质因数
      • 一元线性同余方程
      • 逆元
        • 小费马定理求逆元
        • 拓展欧几里得求逆元
      • 拓展欧几里得
        • 裴蜀定理
        • 线性丢番图方程
        • 拓展欧几里得算法
      • 积性函数
      • 欧拉函数
      • 莫比乌斯函数
      • 狄利克雷卷积
      • 杜教筛
      • 卢卡斯定理
      • 数论分块
      • 威尔逊定理
      • BSGS 大步小歩算法
        • 求指标
    • 多项式与生成函数
    • 线性代数
    • 组合数学
    • 博弈论
  • 计算几何

  • 动态规划

  • 图论

  • 字符串

  • 杂项

  • 算法笔记
  • 数学
martian148
2024-08-31
目录

数论

# 数论

# 素数

素数的定义为只能被 111 和自己整除的正整数

# 素数的判定

小素数时,使用试除法,大素数时使用 Miller_Rabin 算法

# 欧拉筛

欧拉筛是一种线性筛,它能在 O(n)O(n)O(n) 的线性时间内求得 1∼n1\sim n1∼n 内所有素数

欧拉筛的基本原理,一个合数肯定有一个最小质因数,让每个合数只被它的最小质因数筛一次

  1. 检查 2∼n2\sim n2∼n 如果没有被筛过,那么就是素数
  2. 检查到 iii 的时候,利用已经求的的素数去筛掉对应的合数 xxx,而且是用 xxx 的最小质因数去筛
#include <bits/stdc++.h>
using namespace std;
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    int n, q;
    cin >> n >> q;
    vector<int> p;
    vector<bool> vis(n + 1, 0);
    for (int i = 2; i <= n; i++ ){
        if (!vis[i]) p.push_back(i);
        for (int j = 0; j < p.size() && i * p[j] <= n); j++) { // p[j] 就是最小的质因数
            vis[i * p[j]] = 1;
            if (i % p[j] == 0) break;
        }
    }
    while (q--) {
        int x;
        cin >> x;
        cout << p[x - 1] << '\n';
    }
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 分解质因数

显然,我们很容易写出 O(N)O(\sqrt{N})O(N​) 的朴素算法

std::vector<int> breakdown(int x) {
    std::vector<int> res;
    for (int i = 2; i * i <= x; i++) {
        if (x % i == 0) {
            res.push_back(i);
            while (x % i == 0) x /= i;
        }
    }
    if (x != 1)
        res.push_back(x);
    return res;
}
1
2
3
4
5
6
7
8
9
10
11
12

如果提前打出了素数表,那么时间复杂度为 O(Nln⁡N)O(\sqrt{\frac{N}{\ln N}})O(lnNN​​)

# 一元线性同余方程

设 xxx 是未知数,求整数 xxx 满足 ax≡b(modm)ax \equiv b \ (mod \ m)ax≡b (mod m)

不妨设 ax−bax-bax−b 是 mmm 的 −y-y−y 倍,则 ax−b=−my⇒ax+my=bax-b = -my \Rightarrow ax+my = bax−b=−my⇒ax+my=b

这里就转化成了二元线性丢番图方程了

# 逆元

给定整数 aaa,满足 gcd⁡(a,m)=1\gcd(a,m) =1gcd(a,m)=1 称 ax≡1(modm)ax \equiv 1\ (mod \ m)ax≡1 (mod m) 的一个解为 aaa 模 mmm 的逆,记为 a−1a^{-1}a−1

如何求逆

# 小费马定理求逆元

小费马定理: ap−1≡1(modm)a^{p-1} \equiv 1 \pmod{m}ap−1≡1 (modm)

如果在两边同时乘 a−1a^{-1}a−1 得 ap−2≡a−1(modm)a^{p - 2} \equiv a^{-1} \pmod{m}ap−2≡a−1 (modm)

# 拓展欧几里得求逆元

即解同余方程 ax≡1(modp)ax \equiv 1 \pmod{p}ax≡1 (modp)

# 拓展欧几里得

# 裴蜀定理

如果 aaa 与 bbb 均为整数,则有整数 xxx 和 yyy 使得 ax+by=gcd⁡(a,b)ax + by = \gcd(a,b)ax+by=gcd(a,b)

# 线性丢番图方程

先来看二元线性丢番图方程

ax+by=cax + by = cax+by=c

设 d=gcd⁡(a,b)d = \gcd(a,b)d=gcd(a,b) 如果 ddd 不能整除 ccc,那么方程没有整数解,如果 ddd 可以整除 ccc,则方程有无数个整数解

如果存在一个整数解满足 ax0+by0=cax_0 + by_0 = cax0​+by0​=c 那么通解就是 x=x0+(b/d)n,y=y0−(a/d)nx = x_0 + (b/d)n,y=y_0-(a/d)nx=x0​+(b/d)n,y=y0​−(a/d)n,其中 nnn 为任意整数

这里可以把 (b/d)(b/d)(b/d) 看成 Δx\Delta xΔx,把 Δy=(a/d)\Delta y=(a/d)Δy=(a/d)

# 拓展欧几里得算法

我们可以使用拓展欧几里得算法来得到二元线性丢番图方程的一个解

首先我们先考虑解出 ax+by=gcd⁡(a,b)ax+by = \gcd(a,b)ax+by=gcd(a,b)

基本想法是在辗转相除法中,使用 bx0+(a%b)y0=cbx_0 + (a \% b) y_0 = cbx0​+(a%b)y0​=c 的解,来得出 ax+by=cax + by = cax+by=c 的解

前者等于 bx0+(a−b⌊a/b⌋y0)=ay0+b(x0−⌊a/b⌋y0)=cbx_0 + (a - b\lfloor a/b \rfloor y_0) = ay_0 + b(x_0 - \lfloor a/b \rfloor y_0) = cbx0​+(a−b⌊a/b⌋y0​)=ay0​+b(x0​−⌊a/b⌋y0​)=c

对比系数可得 x=y0,y=x0−⌊a/b⌋y0x = y_0, y = x_0 - \lfloor a/b \rfloor y_0x=y0​,y=x0​−⌊a/b⌋y0​

辗转相除法时,当 b=0b=0b=0 时递归结束,显然此时 x=1,y=0x = 1, y = 0x=1,y=0

ll exgcd(ll a, ll b, ll &x, ll &y) {
    if (!b) {
        x = 1, y = 0;
        return a;
    }
    LL d = exgcd(b, a % b, x, y), x0 = x, y0 = y;
    x = y0, y = x0 - a / b * y0;
    return d;
}
1
2
3
4
5
6
7
8
9

此时,我们得到了 ax+by=gcd⁡(a,b)ax + by =\gcd(a,b)ax+by=gcd(a,b) 的一组解,只需要在两边同时乘上 cgcd⁡(a,b)\frac{c}{\gcd(a,b)}gcd(a,b)c​ 就能得到 ax+by=cax+by = cax+by=c 的一组解了

# 积性函数

如果对任意两个互素的正整数 p,qp,qp,q 有 f(pq)=f(p)f(q)f(pq)=f(p)f(q)f(pq)=f(p)f(q) ,fff 称为积性函数

积性函数有一个性质,积性函数的和函数也是积性函数。如果 fff 是积性函数,那么 fff 的和函数 F(n)=∑d∣nf(d)F(n)=\sum\limits_{d|n}f(d)F(n)=d∣n∑​f(d) 也是积性函数

如果 f(n),g(n)f(n),g(n)f(n),g(n) 是积性函数,则 h(n)=f(n)g(n)h(n)=f(n)g(n)h(n)=f(n)g(n) 也是积性函数

常见的积性函数

  • 1(n)1(n)1(n) ,1(n)=11(n)=11(n)=1
  • id(n)id(n)id(n) 单位函数,id(n)=nid(n) = nid(n)=n
  • Ik(n)I_k(n)Ik​(n) 幂函数,Ik(n)=nkI_k(n)=n^kIk​(n)=nk
  • ε(n)\varepsilon(n)ε(n) 原函数 ε(n)=[n=1]\varepsilon(n)=[n=1]ε(n)=[n=1]
  • σ(n)\sigma(n)σ(n) 因数和函数,σ(n)=∑d∣nd\sigma(n)=\sum\limits_{d|n}dσ(n)=d∣n∑​d
  • d(n)d(n)d(n) 约数个数,d(n)=∑d∣n1d(n)=\sum\limits_{d|n}1d(n)=d∣n∑​1

因为积性函数的性质,我们可以考虑把 nnn 质因数分解来求积性函数的第 nnn 项的值

理论上来说,也可以使用欧拉筛来求出 1∼n1\sim n1∼n 的所有值

# 欧拉函数

欧拉函数 ϕ(n)\phi(n)ϕ(n) 定义为不超过 nnn 且 与 nnn 互素的正整数的个数

ϕ(n)=∑i=1n[gcd⁡(i,n)=1] \phi(n) = \sum\limits_{i=1}^n[\gcd(i,n)=1] ϕ(n)=i=1∑n​[gcd(i,n)=1]

欧拉反演:

n=∑d∣nϕ(d) n = \sum\limits_{d|n}\phi(d) n=d∣n∑​ϕ(d)

计算 ϕ(n)\phi(n)ϕ(n) 的通解公式

设 n=p1a1×p2a2×⋯×pkakn = p_1^{a_1}\times p_2^{a_2}\times \cdots \times p_k^{a_k}n=p1a1​​×p2a2​​×⋯×pkak​​,有

ϕ(n)=n(1−1p1)(1−1p2)⋯(1−1pk) \phi(n)=n(1-\frac{1}{p_1})(1-\frac{1}{p_2})\cdots(1-\frac{1}{p_k}) ϕ(n)=n(1−p1​1​)(1−p2​1​)⋯(1−pk​1​)

用欧拉晒求 1∼n1\sim n1∼n 内的所有欧拉函数

通过积性函数的性质 ϕ(p1p2)=ϕ(p1)ϕ(p2)\phi(p_1p_2)=\phi(p_1)\phi(p_2)ϕ(p1​p2​)=ϕ(p1​)ϕ(p2​) 求得,ϕ(p1)\phi(p_1)ϕ(p1​) 和 ϕ(p2)\phi(p_2)ϕ(p2​) 后可以得出 ϕ(p1p2)\phi(p_1p_2)ϕ(p1​p2​)

在欧拉筛的时候,i×pji\times p_ji×pj​ 中 ϕ(i)\phi(i)ϕ(i) 和 ϕ(pj)\phi(p_j)ϕ(pj​) 都是已知的

vector<int> get_phi (int n) {
    vector<int> phi (n + 1);
    vector<bool> vis (n + 1, 0);
    vector<int> prime;
    for (int i = 2; i <= n; i++) {
        if (!vis[i]) {
            vis[i] = 1;
            prime.push_back(i);
            phi[i] = i - 1;
        }
        for (int j = 0; j < prime.size(); j++) {
            if (i * prime[j] > n) break;
            vis[i * prime[j]] = 1;
            if (i % prime[j] == 0) {
                phi[i * prime[j]] = phi[i] * prime[j];
                break;
            }
            phi[i * prime[j]] = phi[i] * phi[prime[j]];
        }
    }
    return phi;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 莫比乌斯函数

莫比乌斯函数的定义为:

μ(n)={1,n=1(−1)r,n=p1p2⋯pn0, others \mu(n) =\begin{cases}1,\ n = 1\\(-1)^r,\ n=p_1p_2\cdots p_n\\0, \ \text{others} \end{cases} μ(n)=⎩⎪⎪⎨⎪⎪⎧​1, n=1(−1)r, n=p1​p2​⋯pn​0, others​

μ(n)\mu(n)μ(n) 是一个积性函数

莫比乌斯函数的和函数:

∑d∣nμ(d)={1,n=10,n=0=[n=1]=ε(n) \sum\limits_{d|n} \mu(d)=\begin{cases}1, n=1\\0,n=0\end{cases}=[n=1]=\varepsilon(n) d∣n∑​μ(d)={1,n=10,n=0​=[n=1]=ε(n)

证明:

设 n=∏i=1kpici,n′=∏i=1kpin=\prod\limits_{i=1}^k p_i^{c_i},n'=\prod\limits_{i=1}^k p_in=i=1∏k​pici​​,n′=i=1∏k​pi​,那么有

∑d∣nμ(d)=∑d∣n′μ(d)=∑i=0k(ki)⋅(−1)i=(1+(−1))k \sum_{d \mid n} \mu(d) = \sum_{d \mid n'} \mu(d) = \sum_{i=0}^{k} \binom{k}{i} \cdot (-1)^i = (1 + (-1))^k d∣n∑​μ(d)=d∣n′∑​μ(d)=i=0∑k​(ik​)⋅(−1)i=(1+(−1))k

可以看出,当且仅当 k=1k=1k=1 也就是 n=1n=1n=1 时,式子等于 111,其他情况下都等于 000

莫比乌斯反演:若 fff 是算数函数,FFF 为 fff 的和函数,对任意正整数 nnn,满足 F(n)=∑d∣nf(d)F(n)=\sum\limits_{d|n}f(d)F(n)=d∣n∑​f(d),有

f(n)=∑d∣nμ(d)F(nd) f(n)=\sum\limits_{d|n}\mu(d)F(\frac{n}{d}) f(n)=d∣n∑​μ(d)F(dn​)

莫比乌斯反演不需要 fff 是积性函数,运用莫比乌斯反演可以将一些函数转化,从而降低计算难度

image.png

e.g. 假设 nnn 个元组成一个环,每个元都是 1,2,⋯,r1,2,\cdots,r1,2,⋯,r 中的一个数,两个环不同当且仅当它们不能通过旋转使得两个环中对应的元素都相等,求有多少个这样的环

在现实题目中,比较常用的是莫比乌斯反演的另外一种形式

设 f,gf,gf,g 且存在正整数 NNN,保证 n>Nn>Nn>N 有 f(n)=g(n)=0f(n)=g(n)=0f(n)=g(n)=0,则

f(n)=∑n∣mg(m)⟺g(n)=∑n∣mμ(mn)f(m) f(n)=\sum\limits_{n|m}g(m)\Longleftrightarrow g(n)=\sum\limits_{n|m} \mu(\frac{m}{n})f(m) f(n)=n∣m∑​g(m)⟺g(n)=n∣m∑​μ(nm​)f(m)

# 狄利克雷卷积

设 fff 和 ggg 是算术函数,记 fff 和 ggg 的狄利克雷卷积为 f∗gf\ast gf∗g ,定义为

(f∗g)(n)=∑d∣nf(d)g(nd) (f\ast g)(n)=\sum\limits_{d|n}f(d)g(\frac{n}{d}) (f∗g)(n)=d∣n∑​f(d)g(dn​)

两个积性函数的狄利克雷卷积仍然是积性函数

莫比乌斯反演很容易写成狄利克雷卷积的形式

f=g∗1⟺g=f∗μ f=g\ast 1\Longleftrightarrow g=f\ast \mu f=g∗1⟺g=f∗μ

狄利克雷卷积满足交换律和结合率

考虑一些公式

  • ε=μ∗1\varepsilon=\mu \ast 1ε=μ∗1
  • id=ϕ∗1\text{id}=\phi \ast 1id=ϕ∗1
  • ϕ=μ∗id\phi =\mu \ast \text{id}ϕ=μ∗id

# 杜教筛

杜教筛用于在低于线性时间里高效求解一些积性函数的前缀和

设 f(n)f(n)f(n) 是一个数论函数,计算 S(n)=∑i=1nf(i)S(n) = \sum\limits_{i=1}^n f(i)S(n)=i=1∑n​f(i)

构造两个积性函数 hhh 和 ggg ,满足 h=g∗fh=g\ast fh=g∗f,根据卷积的定义,有:

h(i)=∑d∣ig(d)f(id) h(i)=\sum\limits_{d|i}g(d)f(\frac{i}{d}) h(i)=d∣i∑​g(d)f(di​)

对 h(i)h(i)h(i) 求和,有

∑i=1nh(i)=∑i=1n∑d∣iig(d)f(id)=∑d=1ng(d)∑d∣inf(id)=∑d=1ng(d)∑i=1⌊nd⌋f(i)=∑d=1ng(d)S(⌊nd⌋) \begin{aligned}\sum_{i=1}^n h(i) &=\sum_{i=1}^n\sum_{d|i}^i g(d)f(\frac{i}{d})\\ &=\sum_{d=1}^ng(d)\sum_{d|i}^n f(\frac{i}{d}) \\ &= \sum\limits_{d=1}^ng(d)\sum\limits_{i=1}^{\lfloor\frac{n}{d}\rfloor} f(i)\\ &= \sum\limits_{d= 1}^n g(d)S(\lfloor\frac{n}{d}\rfloor ) \end{aligned} i=1∑n​h(i)​=i=1∑n​d∣i∑i​g(d)f(di​)=d=1∑n​g(d)d∣i∑n​f(di​)=d=1∑n​g(d)i=1∑⌊dn​⌋​f(i)=d=1∑n​g(d)S(⌊dn​⌋)​

得到

∑i=1nh(i)=∑d=1ng(d)S(⌊nd⌋) \sum_{i=1}^n h(i)=\sum\limits_{d= 1}^n g(d)S(\lfloor\frac{n}{d}\rfloor) i=1∑n​h(i)=d=1∑n​g(d)S(⌊dn​⌋)

为了计算 S(n)S(n)S(n),把等式右边的第 111 项提出来,得到

∑i=1nh(i)=g(1)S(n)+∑d=2ng(d)S(⌊nd⌋) \sum\limits_{i=1}^n h(i)=g(1)S(n)+\sum\limits_{d=2}^n g(d)S(\lfloor\frac{n}{d}\rfloor) i=1∑n​h(i)=g(1)S(n)+d=2∑n​g(d)S(⌊dn​⌋)
g(1)S(n)=∑i=1nh(i)−∑d=2ng(d)S(⌊nd⌋) g(1)S(n)=\sum\limits_{i=1}^n h(i)- \sum\limits_{d=2}^n g(d)S(\lfloor\frac{n}{d}\rfloor) g(1)S(n)=i=1∑n​h(i)−d=2∑n​g(d)S(⌊dn​⌋)

式子中 iii 和 ddd 无关

g(1)S(n)=∑i=1nh(i)−∑i=2ng(i)S(⌊ni⌋) g(1)S(n)= \sum\limits_{i=1}^n h(i)- \sum\limits_{i=2}^n g(i)S(\lfloor\frac{n}{i}\rfloor) g(1)S(n)=i=1∑n​h(i)−i=2∑n​g(i)S(⌊in​⌋)
int prime[maxn];
bool vis[maxn];
int mu[maxn];
LL phi[maxn];

unordered_map <int, int> mu_sum;
unordered_map <int, LL> phi_sum;

void init() {
    int cnt = 0;
    vis[0] = vis[1] = 1;
    mu[1] = phi[1] = 1;
    for (int i = 2; i < maxn; i++) {
        if (!vis[i]) {
            prime[cnt++] = i;
            mu[i] = -1;
            phi[i] = i - 1;
        }
        for (int j = 0l; j < cnt && i * prime[j] < maxn; j++) {
            vis[i * prime[j]] = 1;
            if (i % prime[j] == 0) {
                mu[i * prime[j]] = 0;
                phi[i * prime[j]] = phi[i] * prime[j];
                break;
            }
            mu[i * prime[j]] = -mu[i];
            phi[i * prime[j]] = phi[i] * phi[prime[j]];
        }
    }
    for (int i = 1; i < maxn; i++) {
        mu[i] += mu[i - 1];
        phi[i] += phi[i - 1];
    }
}

int g_sum(int x) {
    return x;
}

LL get_mu_sum (int x) {
    if (x < maxn) return mu[x];
    if (mu_sum.count(x)) return mu_sum[x];
    LL ret = 1;
    for (LL l = 2, r; l <= x; l = r + 1) {
        r = x / (x / l);
        ret -= 1ll * (r - l + 1) * get_mu_sum(x / l);
    }
    return mu_sum[x] = ret;
}

LL get_phi_sum (int x) {
    if (x < maxn) return phi[x];
    if (phi_sum.count(x)) return phi_sum[x];
    LL ret = 1ll * x * (x + 1) / 2;
    for (LL l = 2, r; l <= x; l = r + 1) {
        r = x / (x / l);
        ret -= 1ll * (r - l + 1) * get_phi_sum(x / l);
    }
    return phi_sum[x] = ret;
}

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

# 卢卡斯定理

卢卡斯定义用于计算组合数取模,即求 CnrmodmC_n^r \mod mCnr​ modm,其中 mmm 为素数

编程时常用的卢卡斯定理的形式:

Cnr≡Cnmodmrmodm⋅Cn/mr/m(modm) C_n^r \equiv C_{n\mod m}^{r\mod m}\cdot C_{n/m}^{r/m}\pmod m Cnr​≡Cn modmr modm​⋅Cn/mr/m​ (modm)

# 数论分块

当研究 ∑i=1n⌊ni⌋\sum\limits_{i = 1}^n\lfloor \frac{n}{i} \rfloori=1∑n​⌊in​⌋ 时,暴力求解是 O(n)O(n)O(n) 的,但是我们发现 ⌊ni⌋\lfloor \frac{n}{i}\rfloor⌊in​⌋ 的取值只有少数个

image.png

我们如果能把他们分块一起累计就好了

对于每个块,可以证明 L,RL,RL,R 满足 R=n/(n/L)R = n/(n/L)R=n/(n/L)

现在考虑如何快速计算 ∑i=startend⌊numi⌋\sum\limits_{i=\text{start}}^\text{end}\lfloor \frac{num}{i} \rfloori=start∑end​⌊inum​⌋

// for(int i = st;i<=ed;i++)ans+=num/i
int block(int st, int ed, int num) {
	//sum(num/i i in [st,ed])
	int R = 0;
	int _ans = 0;
	ed = min(ed, num);
	for (int L = st; L <= ed; L = R + 1) {
		R = min(ed, num / (num / i));  //该区间的最后一个数;
		_ans += (R - L + 1)*(num / i); //区间 [L,R] 的 num/i 都是一个值
	}
	return _ans;
}
1
2
3
4
5
6
7
8
9
10
11
12

来看一道例题

codeforces 616E (opens new window)

::: notes

给定两个整数 n,mn,mn,m 求

∑i=1mn mod i \sum_{i=1}^m n \ \text{mod} \ i i=1∑m​n mod i
  • n,m≤1013n,m \le 10^{13}n,m≤1013
  • 答案对 109+710^9+7109+7 取模

:::

把取模写成整除的模式

∑i=1mn mod i=∑i=1mn−⌊ni⌋×i=n×m−∑i=1m⌊ni⌋×i \begin{aligned} \sum_{i=1}^m n \ \text{mod} \ i & = \sum_{i=1}^m n-\lfloor \frac{n}{i}\rfloor \times i\\ &=n \times m - \sum_{i=1}^m \lfloor \frac{n}{i}\rfloor \times i \end{aligned} i=1∑m​n mod i​=i=1∑m​n−⌊in​⌋×i=n×m−i=1∑m​⌊in​⌋×i​
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll MOD = 1e9 + 7;

ll qpow(ll a, ll b, ll mod) {
    ll res = 1;
    while (b) {
        if (b & 1) res = res * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return res;
}

int main() {
    ll n, m; cin >> n >> m;
    int inv2 = qpow(2, MOD - 2, MOD);
    ll ans = 0;
    ll all = n * m % MOD;
    m = min(m, n);
    for (ll L = 1, R; L <= m; L = R + 1) {
        R = min(m, n / (n / L));
        ll len = R - L + 1;
        ll now = (R + L) % MOD * (R - L + 1) % MOD * inv2 % MOD;
        ans = (ans + now * (n / L) % MOD) % MOD;
    }
    cout << (all - ans + MOD) % MOD << endl;
    return 0;
}
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

# 威尔逊定理

若 ppp 为素数,则 ppp 可以整除 (p−1)!+1(p - 1)! + 1(p−1)!+1

(p−1)!≡−1(modm)(p - 1)!\equiv -1 \pmod{m}(p−1)!≡−1 (modm)

# BSGS 大步小歩算法

BSGS 常用于求解离散对数,该算法可以在 O(p)O(\sqrt{p})O(p​) 的时间内求解

ax≡b(modp) a^x\equiv b\pmod{p} ax≡b (modp)

其中要求 gcd⁡(a,p)=1\gcd(a,p)=1gcd(a,p)=1,方程解满足 0≤x<p0\le x < p0≤x<p

令 x=A⌈p⌉−Bx=A\lceil \sqrt{p}\rceil -Bx=A⌈p​⌉−B,其中 0≤A,B≤⌈p⌉0\le A,B \le \lceil \sqrt{p}\rceil0≤A,B≤⌈p​⌉,则有 aA⌈p⌉−B≡b(modp)a^{A\lceil \sqrt{p}\rceil -B}\equiv b\pmod{p}aA⌈p​⌉−B≡b (modp)

变换一下有 aA⌈p⌉≡baB(modp)a^{A\lceil \sqrt{p}\rceil}\equiv ba^B\pmod{p}aA⌈p​⌉≡baB (modp)

已知 a,ba,ba,b 暴力枚举 BBB,把 baBba^BbaB 用 unoreder_map 存下来,然后枚举 AAA,去 map 中配对,从而得到一个解

枚举 A,BA,BA,B 均小于 ⌈p⌉\lceil \sqrt{p}\rceil⌈p​⌉ 所以时间复杂度为 O(p)O(\sqrt{p})O(p​)

# 求指标

已知 a,ba,ba,b 求

xa≡b(modp) x^a\equiv b\pmod{p} xa≡b (modp)

其中 ppp 是个质数

根据原根的知识:gc≡x(modp)g^c\equiv x \pmod{p}gc≡x (modp) 则称 xxx 的指标为 ccc,记作 ind(x)=c\text{ind}(x)=cind(x)=c

所以也就是要求 (gc)a≡b(modp)⇒(ga)c≡b(modp)(g^c)^a\equiv b\pmod{p}\Rightarrow(g^a)^c\equiv b\pmod{p}(gc)a≡b (modp)⇒(ga)c≡b (modp) ,我们已知 g,a,bg,a,bg,a,b ,求 ccc,就转化成第一种模型了

上次更新: 2025/04/08, 18:03:31
珂朵莉树
多项式与生成函数

← 珂朵莉树 多项式与生成函数→

最近更新
01
Java基础语法
05-26
02
开发环境配置
05-26
03
pink 老师 JavaScript 学习笔记
05-26
更多文章>
Theme by Vdoing | Copyright © 2024-2025 Martian148 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式