返回全部文章
·数学

数论算法、定理和常用变换

对欧几里得算法、数论分块、素性测试、同余定理和常用变换的系统整理。

#数学#数论

算法

欧几里得算法

证明

第一种方法是根据更相减损 :

gcd(a,b)=gcd(a,ab)=gcd(b,ab)\gcd(a,b) = \gcd(a,a-b) = \gcd(b,a-b)

更相减损的证明就是 da,dbd \mid a,d \mid bd(ab)d \mid (a-b) ,反之亦然,因此他们的公约数相同,最大公约数相同,得证。

然后根据更相减损每次给 aa 减去 bb 直到 a<ba < b ,这个过程就等价于 aabb 取模。

然后欧几里得算法得证。

第二种方法是 :

不妨假设 a>b a > b 容易发现 : 如果 bab \mid a ,那么 bb 就是两者的最大公约数。

对于不能整除时 : 我们可以设 a=kb+ra = kb + r ,其中 r<br < b

我们要证明的就是 gcd(a,b)=gcd(b,amodb  )\gcd(a,b) = \gcd(b,a \bmod b \; )。过程如下 :

因为 a=kb+ra = kb + r ,所以显然有 r=amodbr = a \bmod b

da,dbd \mid a,d\mid b ,由 c=akbc = a - kb 同除 dd

可得 : rd=adkbd\frac{r}{d} = \frac{a}{d} - k\frac{b}{d}

等号右边显然是整数,因此 drd \mid r ,所以任意 a,ba,b 的公约数也是 amodba \bmod b 的公约数。公约数相同,因此最大公约数也相同。

反过来证明的方法几乎一样 :

dr,dbd \mid r,d\mid b ,由 c=akbc = a - kb 同除 dd

同样可得 :

rd+kbd=ad\frac{r}{d} + k\frac{b}{d} = \frac{a}{d}

式子左侧显然为整数,所以有 dad \mid a ,所以充分性和必要性都得证,我们得出命题等价:

gcd(a,b)=gcd(b,amodb)\gcd(a,b) = \gcd(b,a \bmod b)

于是由这个式子我们显然有了实现 :

实现

namespace way1{
    int gcd(int m,int n)
    {
        int r;
        if (m < n) std :: swap(m,n);
        while(m % n)//辗转相除
        {
            r = m % n;
            m = n;
            n = r;
        }
        return n;
    }
}

namespace way2{
    int gcd(int x,int y)
    {
    	return y ? gcd(y,x % y) : x;
    }
}

namespace way3{
    int gcd(int x, int y)
    {
        while(y ^= x ^= y ^= x %= y);
        return x;
    }
}

(当然可以直接 __gcd )

例题是UVA11426 那就推一下这个例题的式子罢 :

i=1nj=i+1n=j=2ni=1j1gcd(i,j)=d=1nd×j=2ni=1j1[gcd(i,j)=d]=d=1nd×j=2ndi=1j1[ij]=d=1nd×j=2ndφ(j)\begin{split} \sum_{i=1}^n \sum_{j = i+1}^n &= \sum_{j = 2}^n \sum_{i = 1}^{j-1} \gcd(i,j)\\ &= \sum_{d=1}^n d \times \sum_{j=2}^n \sum_{i = 1}^{j-1}[\gcd(i,j) = d] \\ &= \sum_{d=1}^n d \times \sum_{j=2}^{\lfloor \frac{n}{d} \rfloor} \sum_{i=1}^{j-1}[i \bot j]\\ &= \sum_{d=1}^n d \times \sum_{j=2}^{\lfloor \frac{n}{d} \rfloor}\varphi(j)\\ \end{split}

到这里第一步已经成功了,都是经典操作也没什么难度。考虑进一步优化: 设 S(x)=j=2xφ(j),f(x)=j=1xjS(x) = \sum_{j=2}^x \varphi(j) ,f(x) = \sum_{j = 1}^x j .

显然原式变成 :

d=1nd×S(nd)\sum_{d=1}^n d \times S({\lfloor \frac{n}{d} \rfloor})

因为 nd\lfloor \frac{n}{d} \rfloor 被重复计算多次,显然考虑数论分块。

于是原式化为 :

(f(r)f(l1))×S(nl)\sum(f(r) - f(l-1)) \times S(\lfloor \frac{n}{l} \rfloor)

预处理 f(x),S(x)f(x),S(x) 的值,最终对于 TT 次询问总的时间复杂度是 O(n+Tn)O(n + T \sqrt{n} ) ,可以通过本题。

扩展欧几里得算法(exgcd)

推导

由裴蜀定理我们已知 : ax+by=gcd(a,b)ax + by = \gcd(a,b) 一定存在整数解。

使用 exgcd 可以得到上述方程的一组特解。

考虑解这个方程,显然当 b=0b = 0 时我们有 : x=1,yZx = 1,y \in Z

b0b \neq 0 时,我们设:

gcd(a,b)=ax1+by1gcd(b,amodb)=bx2+(amodb)y2=bx2+(aabb)y2\begin{split} &\gcd(a,b) = ax_1 + by_1\\ &\gcd(b,a \bmod b) = bx_2 + (a \bmod b)y_2 = bx_2 + (a - \lfloor \frac{a}{b} \rfloor b)y_2\\ \end{split}

两式左边相等,那么拆开括号就有 :

ax1+by1=ay2+b(x2aby2)ax_1 + by_1 = ay_2 + b(x_2 - \lfloor \frac{a}{b} \rfloor y_2)

两边对应系数得 :

x1=y2,y1=x2aby2x_1 = y_2,y_1 = x_2 - \lfloor \frac{a}{b} \rfloor y_2

成功了!

于是我们就可以像求gcd一样递归求解了

代码实现

按照这个式子写的代码长这样 :

int exgcd(int a,int b,int &x,int &y)
{
    if(!b)
    {
        x = 1;y = 0;
        return a;
    }
    int d = exgcd(b,a % b,x,y);
    int t = x;x = y;
    y = t - a/b * y;
    return d;
}

函数的返回值就是顺便求了一下gcd。

或者这样写 :

void exgcd(int a,int b,int &x,int &y)
{
    if(!b)
    {
       x = 1;y = 0;
       return;
    }
    exgcd(b,a%b,y,x);
    y -= a/b*x;
}

本质上是完全等价的,而且这个板子更好记一些

之后令 g=gcd(a,b)g = \gcd(a,b)lcm(a,b)=ab/g \text{lcm}(a,b) = a * b / gax+lcm(a,b)+bylcm(a,b)=c ax + \text{lcm}(a,b) + by - \text{lcm}(a,b) = c 所以就有 :

a(x+b/g)+b(ya/g)=ca(x + b/g) + b(y - a/g) = c

例题

一个很强的板子是 P5656

题意就是 :

T(T2e5)T(T \le 2e5)组数据,每组给出 a,b,c[1,109]a,b,c \in [1,10^9] ,询问使得 ax+by=cax+by = c 成立的解。

若有正整数解,输出:

  • 正整数解的个数
  • 正整数解中最小的 xx 和最大的 yy
  • 正整数解中最大的 xx 和最小的 yy

否则,若有整数解,输出 :

  • 所有整数解中 xx 的最小正整数值, yy 的最小正整数值

否则,输出 1-1

大概说一下这个题罢,虽然大概所有人都应该会写exgcd,但是能完整解决这道题的我觉得不多(

ax+by=cax + by = c

显然,gcd(a,b)(ax+by)\gcd(a,b) \mid (ax+by)gcd(a,b)c\gcd(a,b) \nmid c 时无解

然后我们就可以由exgcd求出一组整数 x0,y0x_0,y_0 ,使得:

ax0+by0=gcd(a,b)ax_0 + by_0 = \gcd(a,b)

等号两边同除 gcd(a,b)gcd(a,b) 后同乘 cc ,就是 :

ax0cgcd(a,b)+by0cgcd(a,b)=ca \frac{x_0c}{\gcd(a,b)}+ b \frac{y_0c}{\gcd(a,b)} = c

于是我们找到了原方程的一组整数特解 x1,y1x_1,y_1

x1=x0cgcd(a,b),y1=y0cgcd(a,b)x_1 = \frac{x_0c}{\gcd(a,b)},y_1 = \frac{y_0c}{\gcd(a,b)}

接下来考虑构造通解 :

对于 dQ\forall d \in Q ,必然有 :

a(x1+db)+b(y1da)=ca(x_1 + db) + b(y_1 - da) = c

所以对于整数通解只需要保证 da,dbZda,db \in Z

dd 取到最小的可能的正值(实数)时 dx=db,dy=dad_x = db,d_y = da 那么任意解中这两个变量与 x1,y1x_1,y_1 的偏差一定分别是 dxd_xdyd_y 的倍数。

那么显然最小时 dx=bgcd(a,b),dy=agcd(a,b)d_x = \frac{b}{\gcd(a,b)} , d_y = \frac{a}{\gcd(a,b)} ,在 d=1gcd(a,b)d = \frac{1}{\gcd(a,b)} 时取到。

所以通解就是 :

x=x1+sdx,y=y1sdyx = x_1 + sd_x,y = y_1 - sd_y

其中 sZs \in Z

而且 xxyy 取值的变化呈负相关。

显然而重要的 : ss 越大, xx 越大, yy 越小,反之亦然。

考虑是否有正整数解的判定 :

限制 x>0x > 0 ,则 x1+sdx>0,s>x1dxx_1 + sd_x > 0 ,s > -\frac{x_1}{d_x} 限制 y>0y > 0 ,则 y1sdy>0,s<y1dyy_1 - sd_y > 0 ,s < \frac{y_1}{d_y}

所以若要有正整数解,则要满足 :

x1dx<s<y1dy-\frac{x_1}{d_x} < s < \frac{y_1}{d_y}

当这个不等式无解时即无正整数解, ss 位于左端点时即为 xx 的最小正整数值, ss 位于右端点时即为 yy 的最小正整数值。

有解时即为有正整数解,正整数解个数就是在这个范围内的 ss 的个数,容易求得。

xx 的最大值和 yy 的最小值都是在 ss 的右端点取到,xx 的最小值和 yy 的最大值都是在 ss 的左端点取到。

然后这道题就做完了。

代码的话就长这样 :

#include<bits/stdc++.h>
namespace Pozhu{
using namespace std;
typedef long long ll;

ll a,b,c;
ll exgcd(ll a,ll b,ll &x,ll &y);

void main()
{
    cin >> a >> b >> c;
    ll g = __gcd(a,b);
    if(c % g)
    {
        cout << -1 << '\n';
        return;
    }
    ll x,y;
    exgcd(a,b,x,y);
    x *= c / g,y *= c / g;  //x1,y1
    ll dx = b / g,dy = a / g; // x = x1 + sdx,y = y1 - sdy;
    ll low_s = ceil((-x + 1) * 1.0 / dx);
    ll high_s = floor((y - 1) * 1.0 / dy);
    if(high_s >= low_s)
    {
        ll num = high_s - low_s + 1;
        ll max_x = x + high_s * dx;
        ll min_y = y - high_s * dy;
        ll min_x = x + low_s * dx;
        ll max_y = y - low_s * dy;
        cout << num << ' ' << min_x << ' ' << min_y << ' ' << max_x << ' ' << max_y << '\n';
    }
    else
    {
        ll min_x = x + low_s * dx;
        ll min_y = y - high_s * dy;
        cout << min_x << ' ' << min_y << '\n';
    }
    return;
}

ll exgcd(ll a,ll b,ll &x,ll &y)
{
    if(!b)
    {
        x = 1,y = 0;
        return a;
    }
    ll g = exgcd(b,a%b,y,x);
    y -= a / b * x;
    return g;
}

}

signed main()
{
    int T;
    std :: ios :: sync_with_stdio(false);
    for(std :: cin >> T;T;T--)
    Pozhu :: main();
    return 0;
}

类欧几里得算法

欧几里得全家桶(bushi

类欧几里得算法用来解决一些计数问题,尤其是可以出现下取整符号的情况。虽然考的比较少但是很好写~~,有时候可以拿来爆标~~。

推式子的过程有些复杂,写过专门的一篇文章,就放一个link罢。

整除分块

也叫数论分块

放一些简单的东西来缓和一下气氛(

通常来讲我们会在以下场合使用整除分块 :

i=1nni\sum_{i = 1}^n\left \lfloor \frac{n}{i} \right \rfloor

推导

大眼观察可以猜出 ni\left \lfloor \frac{n}{i} \right \rfloor 总是隔一段才变一次(因为是整除)

于是可以考虑以这个变化的位置为分界点进行一个分块,对于每一块我们只进行一次求值,然后乘上块长就可以得到一整块的答案。

假设我们当前的左端点是 ll ,右端点是 rr ,这个区间内单点的值为 kk ,那么就有 :

k=nl=nrk = \left \lfloor \frac{n}{l} \right \rfloor = \left \lfloor \frac{n}{r} \right \rfloor

对于 i[l,r]i \in [l,r] ,显然 rr 是所有 ii 中的最大取值。因为 ikn,inki \ast k \le n, i \le \frac{n}{k} 所以有 :

r=nk=nnlr = \left \lfloor \frac{n}{k} \right \rfloor = \left \lfloor \frac{n}{\left \lfloor \frac{n}{l} \right \rfloor} \right \rfloor

其复杂度是 O(n)O(\sqrt{n}) ,证明会在下面给出

代码实现

for(int l = 1,r;l <= n;l = r + 1)
{
    r = n / (n / l);
    ans = ans + (r - l + 1) * (n / l);
}

要注意到整除分块的适用范围很广,以上模板仅是对于最平凡的场合,而整除分块常见于杜教筛和莫反当中,在相应文章中可以看到整除分块的频繁出现。

复杂度证明

这里给出整除分块的复杂度证明。

对于 :

i=1nni\sum_{i = 1}^n\left \lfloor \frac{n}{i} \right \rfloor

我们把 ii 的取值范围分为两部分进行讨论。

第一部分 : 1in1 \le i \le \sqrt{n} ,容易发现这样的 ii 最多只有 n\sqrt{n} 个,考虑最坏情况,每个 ni\left \lfloor \frac{n}{i} \right \rfloor 的取值都不同,此时块长为 11 ,最多有 n\sqrt{n} 块。

第二部分 : n<in\sqrt{n} < i \le n,容易得到 ni<n\left \lfloor \frac{n}{i} \right \rfloor < \sqrt{n} ,这样的取值最多有 (n1)(\sqrt{n} - 1) 个,意味着最多有 (n1)(\sqrt{n}-1) 块。

于是块数最多为 2n12 \sqrt{n} - 1 ,我们对于每块内求解的复杂度为 O(1)O(1) ,于是总复杂度为 O(n)O(\sqrt{n}) ,得证。

例题

首先是模板题:H(n)

如果有一道题目是专门考察整除分块的,那么你一定很难看出来这是整除分块(

P2261 [CQOI2007]余数求和

给定 n,kn,k ,n,k109n,k \le 10^9,求 :

i=1nkmodi\sum_{i = 1}^n k \bmod i

考虑模的意义是整除取余,于是有 :

ans=i=1n(kiki)ans = \sum_{i = 1}^n (k - i \lfloor \frac{k}{i} \rfloor)

于是做完了,剩下的应该不用说了。

P3935 Calculating

进行一个没有难度的转化题意,发现是求 lrl \sim r 的因数个数之和。复杂度要求至多为根号级别。

考虑一个经典套路,于是我们把题意简化为求 1n1 \sim n 的因数个数之和。

那么考虑计算每一个数的贡献再合并,于是变成了枚举每个因数,统计它的倍数个数再求和。

关于这为什么就是答案,一个简单明了的解释是一个推导过程 :

f(x)=i=1x[ix]\begin{split} f(x) &= \sum_{i = 1}^x[i \mid x]\\ \end{split}

于是答案就是 :

x=1ni=1x[ix]=i=1nni\sum_{x = 1} ^ n \sum_{i = 1}^x[i \mid x] = \sum_{i = 1} ^ n \lfloor \frac{n}{i} \rfloor

最后一步转化是考虑 ii 对于每一个倍数都产生 11 的贡献,于是 ii 的贡献就是其倍数个数。

然后上一个整除分块,这题做完了。

Cipolla 算法

用来解决形如

x2nmodpx^2 \equiv n \mod p

的问题(模意义开根)。其中 pp 为奇素数。

这部分参考Kewth 的博客,具体而言,文章架构和讲述顺序大体一致。

那是一篇优秀的博客,我从那里学会了二次剩余。他大概比我讲的清楚些

解的数量

数学直觉告诉我们解可能不唯一,注意我们讨论的范围是 [0,p)[0,p)

考虑两个不同解 x1,x2x_1,x_2,代入原式易得 x12x22x_1^2 \equiv x_2^2,于是移项使用平方差公式,有 :(x1+x2)(x1x2)0(x_1 + x_2)(x_1 - x_2) \equiv 0

由于他们是不同解,有 x1+x20x_1 + x_2 \equiv 0,于是这两数为模意义下相反数,发现只有两个解。考虑是否有特殊情况,发现当一个解为 00 时只有一解。而剩余情况下,因为模数是奇素数,两数奇偶性不同,两数不可能相同。

这里涉及到一个二次剩余的概念,注意二次剩余是一种数,这个意义建立在一个模数下。对于一个模数 pp,一个非 00 整数 nn,如果 x2nmodpx^2 \equiv n \mod p 存在整数解,那么 nn 是一个二次剩余,否则不是。

同时可以发现每一对相反数都对应一个二次剩余,且这些二次剩余两两不同(若相同则有四个解显然不成立)。于是二次剩余的数量是 p12\frac{p-1}{2},剩下的数都是非二次剩余,数量相同。

欧拉准则

用来判定一个数是否为二次剩余。

不妨认为 nn 的范围是 [0,p)[0,p)

特殊判定 n=0n=0 的情况,它不是二次剩余,它模意义下的根只有一个,是它本身。

判定要用的内容是 :

如果 nn 是二次剩余,当且仅当 n(p12)1n^{(\frac{p-1}{2})} \equiv 1,否则 nn 是非二次剩余,且n(p12)1n^{(\frac{p-1}{2})} \equiv -1

下面是一个证明 :

n(p12)1n ^ {(\frac{p-1}{2})} \equiv 1,那么将 nn 表示为 gkg^k,其中 gg 是模 pp 意义下的原根。

那么 gkp121g^{k \frac{p-1}{2}} \equiv 1。由于 gg 是原根,有 p1kp12p-1 \mid k \frac{p-1}{2},这是阶的性质,可见阶与原根中对于阶性质的介绍。

于是 kk 一定是偶数,那么 x=gk2x = g^{\frac{k}{2}} 即为所求解。

我们通过构造可行解的方法证明了此时的 nn 是二次剩余。

由费马小定理得到 np11n^{p-1} \equiv 1,由于 pp 是奇素数,p1p-1一定是偶数,于是化为 n2(p12)1n^{2(\frac{p-1}{2})} \equiv 1。那么 n(p12)n^{(\frac{p-1}{2})}11 开根的解,于是 n(p12)n^{(\frac{p-1}{2})} 的值只能是 111-1

如果 nn 是二次剩余,那么 x2nx^2 \equiv n 有整数解,那么就有 xp11x^{p-1} \equiv 1

于是我们证明了对于任意一个二次剩余 nn 都有上式成立。

于是我们证明了充分性和必要性,得到 nn 是二次剩余等价于n(p12)1n^{(\frac{p-1}{2})} \equiv 1

实际上有个东西叫勒让德符号,但是与上面的判定方法本质相同,现在的介绍足以解决这一问题,就不再引入新的概念。

那么有了这个引理之后,我们应该如何求解原问题呢?

Cipolla

找到一个 aa 满足 a2na^2 - n 是非二次剩余。非二次剩余的数量大致占一半,于是期望两次可以找到一个合法的 aa,这是一个小常数。

然后定义 i2a2ni^2 \equiv a^2 -n,这并不是二次剩余,于是像是对负数开根那样,我们的 ii 是一个“虚数”,于是可以把所有数表示成 a+bia + bi 的形式,其中 a,b[0,p)a,b \in [0,p)

结论是 (a+i)p+1n(a+i) ^ {p + 1} \equiv n

证明 :

引理1

ipii^p \equiv -i

证明 :

ipi(i2)p12i(a2n)p12ii^p \equiv i (i^2) ^ {\frac{p-1}{2}} \equiv i (a^2 - n) ^ {\frac{p-1}{2}} \equiv -i

得证。

引理2

(A+B)pAp+Bp(A + B) ^ p \equiv A^p + B^p

证明类似 Lucas 定理的证明中对于引理二的证明,用二项式定理展开即可,不再赘述。

有了这两个引理之后我们可以考虑去证明上述结论 :

(a+i)p+1(ap+ip)(a+i)(ai)(a+i)a2i2n(a+i) ^ {p+1} \equiv (a^p + i^p)(a + i) \equiv (a-i)(a+i) \equiv a^2 - i^2 \equiv n

于是得证。

于是 (a+i)p+12(a+i) ^ {\frac{p+1}{2}} 就是一个解,其相反数是另一个解。

但是这是虚数运算,大家当然会产生疑问 : 这个结果的虚部一定为 00 吗?

答案是肯定的。用反证法可以得到这个结论:

假设有 (A+Bi)2n(A + Bi) ^ 2 \equiv nB0B \neq 0

注意为什么我们设这样的形式,原因当然是方便讨论。注意上边的解一定可以找到一个这种形式的叙述表示。

于是 A2+B2i2+2ABinA^2 + B^2i^2 + 2 ABi \equiv n,移项得到 A2+B2(a2n)n2ABiA^2 + B^2(a^2 - n) - n \equiv -2ABi

这里可以运用等式的基本性质,等号左边没有虚部,那么右边的虚部也一定为 00

AB=0AB = 0,已知 B0B \neq 0,那么 A=0A = 0

于是化简式子 :

B2(a2n)nB^2(a^2 - n) \equiv n

也就是 :

i2nB2i^2 \equiv n B^{-2}

B2B^{-2}是一个二次剩余,因为显然有一解为 B1B^{-1}

nn 也是二次剩余,那么 nB2nB^{-2} 显然也是二次剩余,解是原解的乘积。

这与 i2i^2 是非二次剩余矛盾,就像是虚数的 i2>0i^2 > 0 一样离谱。

于是我们得到了矛盾,证明了假设不成立,即不存在那样的 BB,我们求出的解虚部一定为 00

那么我们就可以解决开头提出的问题了。

这是板子题 : P5491 【模板】二次剩余

BSGS算法

BSGS(baby-step giant-step) ,即大步小步算法,常用于求解离散对数问题。也就是说,该算法可以在 O(p)O(\sqrt{p}) 的时间内求解

axb  (modp  )a^x \equiv b \; (\bmod p \; )

普通的BSGS算法要求 apa \bot p ,不要求 pp 是素数。

x=ApB x = A \lceil \sqrt{p} \rceil - B ,其中 0A,Bp 0 \le A,B \le \lceil \sqrt{p} \rceil ,则有 aApBb  (modp  )a^{A \lceil \sqrt{p} \rceil - B} \equiv b \; (\bmod p \;) ,两边同乘 aBa^B ,那么我们得到 :

aApbaB  (modp  )a^{A \lceil \sqrt{p} \rceil} \equiv b \cdot a^B \; (\bmod p \; )

因为我们已知 a,ba,b ,于是我们可以枚举 BB ,预处理出所有 baBba^B 的取值,使用 maphash 建立起相应的映射,然后逐一计算 aApa^{A \lceil \sqrt{p} \rceil} ,也就是枚举 AA ,检查是否有与之对应的 baBba^B ,从而我们可以得到所有的 xxx=ApBx = A \lceil \sqrt{p} \rceil - B

显然由 A,BpA,B \le \sqrt{p} ,上述算法的时间复杂度为 Θ(p)\Theta(\sqrt{p}) ,若使用 map 则多一个 log\log

要求 apa \bot p 的原因 :

我们求得的是 A,BA,B ,而要通过 A,BA,B 的值推出 xx 的值需要 aApbaBaApBb  (modp  )a^{A\lceil \sqrt{p} \rceil } \equiv ba^B \Leftrightarrow a^{A\lceil \sqrt{p} \rceil-B} \equiv b \; (\bmod p \;),即这个同余式对于两边同除 aBa^B 仍成立。

所以必须要有 aBpa^B \bot p ,也就是 apa \bot p

模板题是P3846,代码如下 :

#include<bits/stdc++.h>
namespace Pozhu{
using namespace std;
typedef long long ll;
ll a,x,n,p;

ll ksm(ll ,ll );
ll BSGS(ll ,ll ,ll );

void main()
{
    scanf("%lld%lld%lld",&p,&a,&n);
    ll ans = BSGS(a,n,p);
    if(ans == -1)
        puts("no solution");
    else
        printf("%lld",ans);
    return;
}

ll BSGS(ll a,ll b,ll p)
{
    b %= p;
    map<ll ,ll > has;has.clear();
    ll t = sqrt(p) + 1;
    for(ll j = 0,tmp = b;j<t;tmp = tmp * a % p,j++)
    has[tmp] = j;
    a = ksm(a,t);
    if(!a) return b == 0 ? 0 : -1;
    for(ll i = 1,tmp = a;i<=t;tmp = tmp * a % p,i++)
    if(has.count(tmp))
    return i * t - has[tmp];
    return -1;
}

ll ksm(ll a,ll b)
{
    ll ans = 1;
    for(;b;b>>=1,a = a * a % p) if(b & 1) ans = ans * a % p;
    return ans;
}

}

signed main()
{
    Pozhu :: main();
    return 0;
}

BSGS算法给我们带来的教益不仅是解决了这个问题,还有其根号分治的思想。

灵活运用类似的思想,我们就可以解决这道题: Maximum Sine

提示:转化题意,考虑类似的分块思路。

放一个题解,使这题有头有尾。

扩展BSGS

扩展BSGS依然用来解决这个问题 :

axb  (modp  )a^x \equiv b \;(\bmod p \;)

但是其中 a,pa,p 不一定互质。

apa \bot p 时,在模 pp 意义下 aa 存在逆元,因此可以使用BSGS算法求解(同除 aBa^B 即同乘 aa 的逆元的 BB 次方,可行)。 于是我们想办法让他们变的互质。

我们设 d1=gcd(a,p)d_1 = \gcd(a,p) ,如果 d1bd_1 \nmid b ,则原方程无解。否则我们把方程和模数同时除以 d1d_1 ,得到 :

ad1ax1bd1  (modpd1  )\frac{a}{d_1}\cdot a^{x-1} \equiv \frac{b}{d_1} \;(\bmod \frac{p}{d_1} \; )

如果此时 aapd1\frac{p}{d_1} 仍不互质就再除,设 d2=gcd(a,pd1)d_2 = \gcd(a,\frac{p}{d_1}) 。如果 d2bd1d_2 \nmid \frac{b}{d_1} ,则原方程无解,否则同时除以 d2d_2 得到 :

a2d1d2ax2bd1d2  (modpd1d2  )\frac{a^2}{d_1d_2}\cdot a^{x-2} \equiv \frac{b}{d_1d_2} \;(\bmod \frac{p}{d_1d_2} \; )

不停地这样做下去,直到 apd1d2dka \bot \frac{p}{d_1d_2\cdots d_k}

D=idiD = \prod_id_i ,那么原方程就是 :

akDaxkbD  (modpD  )\frac{a^k}{D} \cdot a^{x-k} \equiv \frac{b}{D} \; (\bmod \frac{p}{D} \; )

apDa \bot \frac{p}{D} 可得 akDpD\frac{a^k}{D} \bot \frac{p}{D} ,这样 akD\frac{a^k}{D} 就有逆元了,方程两边同乘它的逆元,问题就转化为一个普通的BSGS问题,解出 xkx-k 的值之后再加上 kk 就是要求的解。

但是可能会出现 xkx \le k 的情况,我们可以在知道 kk 之后直接进行 kk 次枚举验证答案来避免这种情况对求解造成影响。

模板题是 P4195 ,代码很不优美就不放了。

BSGS解高次剩余

求解

xab  (modp  )x^a \equiv b \;(\bmod p \; )

其中 pp 为质数。

该模型可以通过一系列转化变为BSGS的基本形式。

前置知识是阶和原根。

由于式子中的 pp 为质数,那么一定存在原根 gg ,因此对于模 pp 意义下任意的数 x(0xp)x(0 \le x \le p) 有且仅有一个数 ii 满足 x=gix = g^i

Pollard Rho 算法

Fermat 素性测试

Miller-Rabin 素性测试


定理

算数基本定理(唯一分解定理)

任意不是质数的正整数 aa 能唯一分解为有限个质数幂的乘积 :

a=1impicia = \prod_{1 \le i \le m} p_i^{c_i}

约数个数定理

“小学奥数”

内容

对于一个大于 11 的正整数 nn 可以分解质因数 :

n=i=1kpiai=p1a1p2a2pkakn = \prod_{i = 1}^k p_i^{a_i} = p_1^{a_1} \cdot p_2^{a_2} \cdots p_k ^ {a_k}

nn 的正约数个数就是 :

τ(n)=i=1k(ai+1)=(a1+1)(a2+1)(ak+1)\tau(n) = \prod_{i = 1}^k (a_i + 1) = (a_1 + 1)(a_2 + 1) \cdots (a_k + 1)

证明

对于上述唯一分解的结果观察 :

p1a1p_1^{a_1} 的约数有 : p10,p11p1a1p_1^0,p_1^1 \cdots p_1^{a_1}(a1+1)(a_1 + 1) 个,其他质因子同理。

于是总的因子个数可以由乘法原理得到 :

τ(n)=i=1k(ai+1)=(a1+1)(a2+1)(ak+1)\tau(n) = \prod_{i = 1}^k (a_i + 1) = (a_1 + 1)(a_2 + 1) \cdots (a_k + 1)

得证。

例题可以是 欧拉计划 T12 ,答案易求,这里不放了。

裴蜀定理

(又称贝祖定理)

对于任意不全为零的整数 a,ba,bx,yZ\exists x,y \in Z ,使得 ax+by=gcd(a,b) ax+by = \gcd(a,b)

对于不定方程 ax+by=max + by = m ,其有解的充要条件是 gcd(a,b)m\gcd(a,b) \mid m

证明

充分性

即证明 : gcd(a,b)m\gcd(a,b) \mid m ,则 ax+by=max+by=m 有整数解

假设我们已知 ax+by=gcd(a,b)ax+by = \gcd(a,b) 有一组整数解 x0,y0x_0,y_0 那么显然 ax+by=max+by = m 存在一组整数解 x1=x0mgcd(a,b),y1=y0mgcd(a,b)x_1 = x_0 \frac{m}{\gcd(a,b)} ,y_1 = y_0 \frac{m}{\gcd(a,b)} ,于是只需证明 ax+by=gcd(a,b)ax+by = \gcd(a,b) 一定存在整数解。

然后就可以从网上随便找一篇证明贺一下了

因为大家写的都是一样的而且都没有出处,我也不知道这个证明最先是在哪给出来的qwq,但是有些人写出锅的地方我还是能浅修一下。

d=gcd(a,b)d = \gcd(a,b),显然有 da,db,dax+byd \mid a,d \mid b,d \mid ax+by

ssax+byax+by 的最小正数值,设 q=asq = \lfloor \frac {a}{s} \rfloor

于是我们有 r=amods=aqs=aq(ax+by)=a(1qx)+b(qy)r = a \bmod s = a - qs = a - q(ax+by) = a(1-qx) + b(-qy)

所以 rr 也是 ax+byax+by 的一个取值,并且由取模的来源我们已知 0r<s0 \le r < s,不难得到 r=0r = 0 ,于是由此我们得到 sas \mid a ,同理可得 sbs \mid b ,于是 sgcd(a,b)s \mid \gcd(a,b),即 sds \mid d

又因为 dax+byd \mid \forall ax+by ,而 ssax+byax+by 的一个取值,所以 dsd \mid s

于是证得 s=ds = d (这里已经直接证明了下边的推论三)

于是因为 ssax+byax+by 的一个取值,ddax+byax+by 的一个取值。

换言之 ax+by=gcd(a,b)ax+by = \gcd(a,b) 一定存在整数解。

于是我们证明了这一结论。

必要性

即证明 : ax+by=max + by = m 有解,必定有 gcd(a,b)mgcd(a,b) \mid m (比较显然)

gcd(a,b)a\gcd(a,b) \mid a gcd(a,b)b\gcd(a,b) \mid b

所以 gcd(a,b)m=ax+by\gcd(a,b) \mid m = ax+by

应用

zh_dou : 用来做题

可以用来证明奇奇怪怪的东西和推式子 信息上对于这东西常见的套路是枚举gcd 如: 给你T组数据,求 i=1nj=1mgcd(i,j)\sum_{i = 1}^n \sum_{j = 1}^m \gcd(i,j) 其中有一步是标准的枚举gcd(经典枚举gcd)

i=1nj=1mgcd(i,j)=i=1nj=1mdi,jd[gcd(id,jd)=1]\begin{split} & \sum_{i = 1}^n \sum_{j = 1}^m \gcd(i,j)\\ = & \sum_{i = 1}^n \sum_{j = 1}^m \sum_{d \mid i,j} d [\gcd( \frac{i}{d} , \frac{j}{d}) = 1] \end{split}

一些推论

一、aa,bb可以组成所有 gcd(a,b)\gcd(a,b) 的倍数(其实是定理的直接结论,等式的基本性质)

二、 abx,yZ,ax+by=1a\bot b \Longleftrightarrow \exists x,y \in Z, ax+by=1

三、 ax+byax+by 的最小正整数取值为 gcd(a,b)\gcd(a,b)

四、 对于不定方程 x1y1+x2y2++xnyn=k,yiZx_1y_1 + x_2y_2 + \cdots + x_ny_n = k,y_i \in Z ,其有解的充要条件为 gcd(xi)k\gcd({x_i}) \mid k

五、我们考察不定方程 ax+by=nax+by = n ,其中 aba \bot b 若这个方程有一组解使得 x0,y0x \ge 0,y \ge 0 ,那么称 nn 可以被 a,ba,b 表示。

那么 :

对于互质的 a,ba,b ,记 C=ababC = ab-a-b 。由 aabb 互质, CC 必然为奇数。则有结论 : 对任意的整数 nnnnCnC-n 中有且仅有一个可以被表示

(对称性)

所以对称性总结一下就是 :

可表示的数与不可表示的数在区间 [0,C][0,C] 对称(关于 CC 的一半对称)。00 可被表示,CC 不可被表示;负数不可被表示,大于 CC 的数可被表示。

证明 :

由于 aba \bot b ,原方程有整数解(gcd(a,b)=1,ax+by=n×gcd(a,b)\gcd(a,b) = 1,ax + by = n \times \gcd(a,b)) 。 设一组特解为 x=x0,y=y0x= x_0,y = y_0 则通解为:

{x=x0+bty=y0at\left\{\begin{matrix} x = x_0 + bt \\ y = y_0 - at \end{matrix}\right.

其中 tZt \in Z 。不难发现我们可以通过调整 tt 的取值使得 y[0,a1]y \in [0,a-1] ,这只需要在 y0y_0 上加减若干个 aa 。此时我们的 yy 已经满足条件了。

第一步 : 首先我们证明大于 CC 的数都可以被表示。当 nn 大于 CC 时:

ax=nby>ababbyababb(a1)=aax = n-by > ab-a-b-by \ge ab-a-b-b(a-1) = -a

也就是说:

ax>a,x>1ax > -a,x > -1

因为 xx 为整数,所以得到 xx 为非负整数, nn 可以被表示。

第二步 : 证明 CC 不可被表示,进而 nnCnC-n 不可能都被表示。 考虑反证法。

CC 可以被表示,也就是说 ax+by=ababax+by = ab-a-b 有非负整数解 x,yx,y 。则 :

ab=a(x+1)+b(y+1)ab = a(x+1) + b(y+1)

一个我并不喜欢的版本:

因为 aba \bot b ,要使等式成立,显然有 :

ay+1,bx+1a \le y+1,b \le x+1

(实际上大概连等号都挂不上罢)

aba \bot b ,且等号右边可以合并同类项,所以我们有 :

a(y+1),b(x+1)a \mid (y + 1),b \mid (x + 1)

显然上式化为 :

ab=a(x+1)+b(y+1)ab+ab=2abab = a(x + 1) + b(y + 1) \ge ab + ab = 2ab

abab 显然不为0,矛盾。因此证得 CC 不可能被表示。

(显然并不显然)

显然当 yy 取值最小的时候对应的 xx 取值最大

且由上述证明可知存在最小的 y[0,a1]y \in [0,a-1]

那么下式取 y[0,a1]y \in [0,a-1] ,可以得到最大的 xx

a(x+1)=abb(y+1)=b(ay1)0a(x + 1) = ab - b(y + 1) = b(a - y - 1) \le 0

a>0a > 0x1x \le -1 ,不成立,则 CC 不可以被表示,故得证。

因为 yy 取最大值

此时若 nnCnC-n 都能被表示,则 nn 也能被表示,矛盾。因此我们得到 nnCnC - n 不可能都被表示。

所以第二步完成了

第三步 : 证明如果 nn 不可以被表示,则 CnC-n 一定能被表示 (即 nnCnC-n 一定有一个能被表示)

由上可知 : 若 nn 不可能被表示,因为我们已经保证了有合法的 yy ,那么此时一定有 x<0x < 0 。所以:

Cn=ababaxby=a(x1)+b(a1y)C - n = ab-a-b-ax-by = a(-x-1) + b(a-1-y)

所以 X1-X-1a1ya-1-y 均为非负,则 CnC-n 可以被表示。

所以我们证明了对称性

费马小定理

pp 为素数, gcd(a,p)=1gcd(a,p) = 1 , 则 ap11 (modp  )a^{p-1} \equiv 1 \space (\bmod p \;)。 另一个等价的形式是 : 对于任意整数 aa ,有 apa (modp  )a^p \equiv a \space (\bmod p \; )

证明

设一个质数 pp ,我们取一个不为 pp 倍数的数 aa。 构造一个序列 : A=1,2,3,,p1A = {1,2,3,\cdots,p-1},显然这个序列有这样一个性质 :

i=1nAii=1n(Ai×a) (modp  )\prod_{i=1}^nA_i \equiv \prod_{i = 1}^n (A_i \times a )\space ( \bmod p\; )

对性质的证明 :

(Ai,p)=1\because (A_i,p) = 1 (Ai×a,p)=1\therefore (A_i \times a,p) = 1

又因为每个 (Ai×a) (modp  )(A_i \times a )\space ( \bmod p \;) 都不同,且 (Ai×a) (modp  )<p(A_i \times a )\space ( \bmod p \;) < p 于是每一个 Ai×aA_i \times a 都对应了一个 AiA_i 所以 (Ai×a) (modp  )(A_i \times a )\space ( \bmod p \;) 的取值取遍了 [1,p1][1,p-1]f=(p1)!f = (p-1)! ,则 fa×A1×a×A2××a×Ap1(modp  )f \equiv a \times A_1 \times a \times A_2 \times \cdots \times a \times A_{p-1} ( \bmod p \;)

ap1×ff(modp  )a^{p-1} \times f \equiv f ( \bmod p \;)

所以

ap11(modp  )a^{p-1} \equiv 1 ( \bmod p \;)

故得证。我认为这个证明方法是最简单的一种。

另外的证明方法是由于 mm 为质数,对于欧拉定理代入 φ(m)=m1\varphi(m) = m-1 即可得到费马小定理。

euler定理

译名 : 欧拉定理

内容

gcd(a,m)=1\gcd(a,m) = 1,则 aφ(m)1(modm)a^{\varphi(m)} \equiv 1 (\bmod m)

证明

构造一个模 mm 意义下的简化剩余系 r1,r2,,rφ(m)r_1,r_2,\dots,r_{\varphi(m)},由于 ama \bot m,不难得到 ar1,ar2,,arφ(m)ar_1,ar_2,\dots,ar_{\varphi(m)} 同样为模 mm 意义下的简化剩余系。

于是有乘积相等(简系的元素相同): r1r2rφ(m)ar1ar2arφ(m)aφ(m)r1r2rφ(m)r_1 \cdot r_2 \cdot \dots \cdot r_{\varphi(m)} \equiv ar_1 \cdot ar_2 \cdot \dots \cdot ar_{\varphi(m)} \equiv a^{\varphi(m)} \cdot r_1 \cdot r_2 \cdot \dots \cdot r_{\varphi(m)}

那么两边消去简系之积得到:

aφ(m)1(modm)a^{\varphi(m)} \equiv 1 (\bmod m)

于是欧拉定理得证。

欧拉定理本身的应用较少,更多被应用的是扩展欧拉定理。

那么下面我们来介绍扩展欧拉定理的内容。

扩展euler定理

内容

ab{abmodφ(m)gcd(a,m)=1abgcd(a,m)1,b<φ(m)a(bmodφ(m))+φ(m)gcd(a,m)1,bφ(m)(modm)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 \ge \varphi(m) \end{cases} (\bmod m)

第二行表示此时不能降幂,对于一般问题下的 mm,此时的范围已经足够小,我们可以接受直接求解的复杂度。

实际上扩展欧拉定理的形式优美,易于记忆,即使不了解证明,在很大程度上应用也不会受到限制。

倘若想要了解详细的证明过程,可以参考 oi-wiki 中的内容(尽管这里也是引用的证明)。

受到一些限制,这里暂不展开描述扩展欧拉定理的证明。

放一下模板题:P5091 【模板】扩展欧拉定理

然后可以尝试做一下这题:P4139 上帝与集合的正确用法

wilson定理及扩展

译名 : 威尔逊定理

内容

对于素数 pp 有 :

(p1)!1(modp  )(p-1)! \equiv -1 (\bmod p \;)

证明

oi-wiki上的证明看起来很严谨,这里随便给出一个证明 :

2p22 \sim p-2 的数在模 pp 意义下都有唯一逆元,且不是本身,于是它和逆元配对消掉,剩下的只有 11p1p-111 没有贡献, p11p-1 \equiv -1,于是定理得证。

二项式定理

内容

二项式定理表明了二项式幂次展开后的各项系数:

(a+b)n=i=0n(ni)anibi(a+b)^n = \sum_{i = 0}^n \binom{n}{i}a^{n-i}b^i

证明

n=1n = 1 时,结论显然成立。

当结论对于 n1n - 1 成立时:

(a+b)n=(a+b)n1(a+b)=(i=0n1(n1i)ani1bi)(a+b)=i=0n1(n1i)anibi+i=0n1(n1i)ani1bi+1=i=0n1(n1i)anibi+i=1n(n1i1)anibi=(n10)anb0+i=1n1(ni)anibi+(n1n1)a0bn\begin{split} (a+b)^n &= (a+b)^{n-1} * (a+b)\\ &= \left ( \sum_{i = 0}^{n-1} \binom{n-1}{i} a^{n-i-1} b^i \right ) (a+b)\\ &= \sum_{i = 0}^{n-1} \binom{n-1}{i} a^{n-i} b^i + \sum_{i = 0}^{n-1} \binom{n-1}{i} a^{n-i-1} b^{i+1}\\ &= \sum_{i = 0}^{n-1} \binom{n-1}{i} a^{n-i} b^i + \sum_{i = 1}^{n} \binom{n-1}{i-1} a^{n-i} b^{i}\\ &= \binom{n-1}{0} a^nb^0 + \sum_{i = 1}^{n-1} \binom{n}{i} a^{n-i}b^i + \binom{n-1}{n-1}a^0 b^n \end{split}

其中用到了 (nk)+(nk1)=(n+1k)\binom{n}{k} + \binom{n}{k-1} = \binom{n+1}{k} 的结论。

易得 :

(n10)anb0=(n0)anb0\binom{n-1}{0} a^nb^0 = \binom{n}{0}a^nb^0 (n1n1)a0bn=(nn)a0bn\binom{n-1}{n-1}a^0 b^n = \binom{n}{n}a^0b^n

于是我们有:

(a+b)n=i=0n(ni)anibi(a+b)^n = \sum_{i = 0}^n \binom{n}{i} a^{n-i}b^i

于是此时结论对 nn 也成立。

由数学归纳法证得结论成立。

广义二项式定理

牛顿还将二项式定理推广到了幂为一般实数的情形。

内容

(x+y)a=k=0+(ak)xakyk(x + y) ^ a = \sum_{k = 0}^{+\infty} \binom{a}{k}x^{a-k}y^k

其中 aa 可以取任意实数, (a0)=1\binom{a}{0} = 1

中国剩余定理

中国剩余定理又称孙子定理,英文简写为CRT。

主要作用是求解线性同余方程组(也叫模线性方程组)。

像这样 :

{xa1  (modn1  )xa2  (modn2  )xak  (modnk  )\left\{\begin{matrix} x \equiv a_1 \;( \bmod n_1 \;) \\ x \equiv a_2 \;( \bmod n_2 \;) \\ \vdots\\ x \equiv a_k \;( \bmod n_k \;) \\ \end{matrix}\right.

普通的CRT要求模数之间两两互质。

流程

  1. 计算所有模数的乘积 NN
  2. 对于第 ii 个方程 :a. 计算 mi=Nnim_i = \frac{N}{n_i}b. 计算 mim_i 在模 nin_i 意义下的逆元 mi1m_i^{-1}c. 计算 ci=mimi1c_i = m_im_i^{-1}NN 取模
  3. 方程组模 NN 意义下的唯一解为 : x=i=1kaicix = \sum_{i=1}^{k} a_ic_i

模板题是 P1495

代码如下 :

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,r[20] , a[20], N = 1,ans;
void exgcd(ll a, ll b, ll &x, ll & y){
    if(!b){
        x = 1;
        y = 0;
        return;
    }
    exgcd(b,a%b,x,y);
    ll t = x;
    x = y;
    y = t- (a/b) * y;
}
int main()
{
    cin>>n;
    for(int i= 1;i<=n;i++)
    scanf("%lld%lld",&r[i],&a[i]),N *= r[i];
    for(int i = 1;i<=n;i++)
    {
        ll m = N / r[i],b,y;
        exgcd(m,r[i],b,y);
        if(b < 0) b += r[i];
        ans = (ans + a[i] * m * b);
    }
    cout<<ans%N;
}

(注意代码中输入的第一个数是模数,第二个数是余数。)

证明

要证明CRT的正确性,我们只需要证明通过上述过程算出来的 xx 满足每一个同余方程。

对于不相等的 iijj ,我们显然有 nimjn_i \mid m_j ,即 mj0  (modni  )m_j \equiv 0 \;(\bmod n_i \;)

于是 : cjmj0  (modni  )c_j \equiv m_j \equiv 0 \;(\bmod n_i \;)

又有 : cimi(mi1  mod  ni)1  (modni  )c_i \equiv m_i \cdot (m_i^{-1} \; \text{mod} \; n_i) \equiv 1 \;(\bmod n_i \;)

所以我们可以得到 :

xj=1kajcj(modni  )aici(modni  )aimi(mi1modni  )(modni  )ai(modni  )\begin{aligned} x & \equiv \sum_{j=1}^{k} a_{j} c_{j} & &\left(\bmod n_{i} \; \right) \\ & \equiv a_{i} c_{i} & &\left(\bmod n_{i} \; \right ) \\ & \equiv a_{i} \cdot m_{i} \cdot\left(m_{i}^{-1} \bmod n_{i} \; \right ) & &\left(\bmod n_{i} \; \right) \\ & \equiv a_{i} & &\left(\bmod n_{i} \; \right) \end{aligned}

于是当 ii 取遍 1k1 \sim k 时,我们求得的 xx 都是对应方程的合法解,于是我们证明了这个算法的正确性。

我们对输入的 aia_i 没有特殊限制,因此对于任何一组输入的 ai{a_i} 都对应一个解 xx

xyx \neq y ,则总存在一个 ii 使得 xxyy 在模 nin_i 下不同余。

扩展中国剩余定理

扩展中国剩余定理的简写为 EXCRT ,用来处理 CRT 中模数不互质的情况。

推荐一手 阮行止的博客 ,写的很详细。

设两个方程分别为 :

xa1(modm1  )x \equiv a_1 (\bmod m_1 \; ) xa2(modm2  )x \equiv a_2 (\bmod m_2 \; )

我们把同余方程转化成不定方程 :

x=m1k1+a1=m2k2+a2    k1,k2Zx = m_1k_1 + a1 = m_2k_2 + a_2 \;\; k_1,k_2 \in Z

于是有 :

m1k1m2k2=a2a1m_1k_1 - m_2k_2 = a_2 - a_1

由裴蜀定理可得 : 当 a2a1a_2 - a_1 不能被 gcd(m1,m2)\gcd(m1,m2) 整除时,方程无解。

其他情况下,我们可以使用 exgcdexgcd 求出一组可行解 (k1,k2)(k_1,k_2) ,具体流程如下 :

d=gcd(m1,m2)d = \gcd(m_1,m_2) , p1=m1dp_1 = \frac{m_1}{d} , p2=m2dp_2 = \frac{m_2}{d} ,于是上式等价于 :

k1p1k2p2=a2a1dk_1p_1 - k_2p_2 = \frac{a_2 - a_1}{d}

等号右边是整数。

x0p1+y0p2=1x_0 p_1 + y_0 p_2 = 1

假设我们求得了这个方程的一组解 (x0,y0)(x_0,y_0),那么我们就显然求出了 k1,k2k_1,k_2

k1=a2a1dx0,k2=a2a1dy0k_1 = \frac{a_2 - a_1}{d}x_0,k_2 = - \frac{a_2 - a_1}{d}y_0

于是 :

x=a1+k1m1=a1+a2a1dx0m1x = a_1 + k_1 m_1 = a_1 + \frac{a_2 - a_1}{d}x_0m_1

于是我们构造出了一个符合条件的解,下面我们考虑构造出整个解系 :

我们有定理 :

若有特解 xx' ,那么上述两个线性同余方程构成的同余方程组的通解是 : x+klcm(m1,m2)x'+k\cdot \text{lcm}(m_1,m_2) ,也就是 :

xx(modlcm(m1,m2))x \equiv x' (\bmod \text{lcm}(m_1,m_2))

这个通解的正确性是显然的,然而我们需要考虑的问题是它是否全面,即为何一个 lcm(m1,m2)\text{lcm}(m_1,m_2) 当中只会有一个解的问题。

为了解决这个唯一性问题,我们通常采取反证法 : 假设 x,yx,y 都是满足条件的解,然后证明 x=yx = y ,那么就可以证明唯一性。

设上述问题中存在 0x,ylcm(m1,m2)0 \le x,y \le \text{lcm}(m_1,m_2) ,都使得原同余方程组成立。

不妨设 xyx \ge y ,那么立即可以发现 :

xy0(modm1  )x - y \equiv 0 (\bmod m_1 \; ) xy0(modm2  )x - y \equiv 0 (\bmod m_2 \; )

也就是 :

lcm(m1,m2)(xy)\text{lcm}(m_1,m_2) \mid (x-y)

因为 x,yx,y 都是小于 lcm(m1,m2)\text{lcm}(m_1,m_2) 的数,他们作差也一定小于 lcm(m1,m2)\text{lcm}(m_1,m_2) ,又有整除,于是 xy=0,x=yx - y = 0,x = y ,得证。

则原来两个方程组成的方程组的解为 xb(modM)x \equiv b (\bmod M) ,其中 b=m1k1+a1b = m_1k_1 + a_1 , M=lcm(m1,m2)M = \text{lcm}(m_1,m_2)

对于有多个方程的情况,我们使用相同的方法对它进行两两合并,就可以解出同余方程组了。

模板题是P4777

代码如下 :

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 1e6;
int n,x,y,A,B,C;
int m[maxn],a[maxn],ans;

int qmul(int a,int b,int mo){
    int ans = 0,base = a;
    while(b){
        if(b&1) ans = (ans+base) %mo;
        base = (base+base) %mo;
        b >>= 1;
    }
    return ans;
}

int exgcd(int a,int b,int &x,int &y) {
    if(!b) {
        x=1, y=0;
        return a;
    }
    int g = exgcd(b,a%b,x,y);
    int tx = x;
    x = y;
    y = tx-(a/b)*y;
    return g;
}
signed main()
{
    scanf("%lld",&n);
    for(int i = 1; i <= n; i++)
    scanf("%lld%lld",&m[i],&a[i]);
    for(int i = 2; i <= n; i++) {
        A = m[1], B = m[i], C = a[i]-a[1];
        C = (C%B+B)%B;
        int g = exgcd(A,B,x,y);
        x = qmul(x,(C/g),B);
        x = (x%B+B)%B;
        a[1] = a[1]+ qmul(m[1],x,m[1]*(m[i]/g));
        m[1] = m[1]*(m[i]/g);
        a[1] = (a[1]%m[1]+m[1])%m[1];
    }
    printf("%lld",a[1]);
	return 0;
}

(代码中的 qmul 是龟速乘)

Lucas定理

译名 : 卢卡斯定理

用于解决大组合数取模问题的定理,要求模数必须为素数。

内容如下 :

(nm)(modp  )=(n/pm/p)×(nmodpmmodp)  (modp  )\binom{n}{m} ( \bmod p \; ) = \binom{n/p}{m/p} \times \binom{n \bmod p}{m \bmod p} \; ( \bmod p \; )

实现

代码通常这样写 :

ll lucas(ll n,ll m,ll p)
{
    if(m == 0) return 1ll;
    return C(n % p,m % p,p) * lucas(n / p,m / p,p) % p;
}

其中 CC 是求组合数的函数,它的实现方式由题目数据范围而定。

时间复杂度是 O(f(p)+g(n)log  n)O(f(p)+g(n) \log \; n) ,其中 f(n)f(n) 是预处理组合数的复杂度, g(n)g(n) 是单次求组合数的复杂度。

证明

先推荐一篇写得很好的博客一份关于Lucas定理的简要证明(我就是从这看懂的)

首先需要两个引理 :

引理一

pp 为质数,对于任意的 k[1,p1]k \in [1,p-1] ,我们有 :

Cpk0  (modp  )C_p^k \equiv 0 \; ( \bmod p \; )

证明 :

Cpk=p!k!×(pk)!C_p^k = \frac{p!}{k! \times (p-k)!}

因为 pkp \bot k ,所以分子中不含有 pppp 的真因数,即不可约去 pp 这一项,于是原式的值有因子 pp ,在模 pp 意义下值为 00

引理二

pp 为质数,则对于任意正整数 xx 都有 :

(1+x)p1+xp  (modp  )(1+x)^p \equiv 1 + x^p \; ( \bmod p \; )

证明需要用到二项式定理 :

(1+x)pi=0pcpixi  (modp  )(1 + x) ^ p \equiv \prod_{i=0}^p c_p^i \cdot x^i \; ( \bmod p \; )

由引理一,可以约去 Cp1Cpp1C_p^1 \sim C_p^{p-1} 项,于是就有 :

(1+x)p1+xp  (modp  )(1 + x) ^ p \equiv 1 + x^p \; ( \bmod p \; )

于是我们利用以上两个引理来证明Lucas定理 :

由二项式定理,有 :

(1+x)ni=0nCnixi  (modp  )(1 + x)^n \equiv \sum_{i = 0}^nC_n^i \cdot x_i \;( \bmod p \; )

我们使用带余除法,也就是 n=qnp+rn,m=qmp+rmn = q_n \cdot p + r_n , m = q_m \cdot p + r_m ,那么就有 :

(1+x)n(1+x)qnp+rn[(1+x)p]qn(1+x)rn  (modp  )(1+x)^n \equiv (1+x) ^ {q_n \cdot p + r_n} \equiv [(1+x)^p]^{q_n} \cdot (1+x)^{r_n} \; ( \bmod p \; )

用二项式定理展开 :

i=0nCnixi(j=0qnCqnjxpj)(k=0rnCrnkxk)\sum_{i=0}^nC_n^i \cdot x_i \equiv \left( \sum_{j = 0}^{q_n} C_{q_n}^j \cdot x ^ {p \cdot j} \right ) \left ( \sum_{k = 0}^{r_n} C_{r_n}^k \cdot x ^ k \right )

此时我们观察这个式子 :

CnmC_n^m 就是左式 xmx^m 项的系数,它唯一对应着右侧 j=pm,k=rmj = p_m,k = r_m 的情况,因为只有此时能乘出来 xppmxrm=xmx^{p \cdot p_m} \cdot x^{r_m} = x^m

我们把 j,kj,k 的取值代入,就有了 :

CnmCqnqmCrnrmCnpmpCnmodpmmodp  (modp  )C_n^m \equiv C_{q_n}^{q_m} \cdot C_{r_n}^{r_m} \equiv C_{\lfloor \frac{n}{p} \rfloor} ^ {\lfloor \frac{m}{p} \rfloor} \cdot C_{n \bmod p} ^ {m \bmod p} \; (\bmod p\; )

于是Lucas定理得证

扩展Lucas定理

(exLucas)

Lucas定理要求模数 pp 必须为素数,对于不是素数的模数 pp ,我们可以使用exLucas。

(以下部分来自marchkid_joe):

  1. 引入

在解决问题时,会遇到模数不是质数的情况,便又有了拓展卢卡斯的定理(EXLucas)。(拓展卢卡斯和卢卡斯没关系)。

仍然是这个问题,出题人又不保证 pprimep\in prime

CnmmodppNC_{n}^{m}\bmod p \qquad p\in N^*
  1. 具体流程
  • 中国剩余定理
  • 逆元

(可以看出 ExLucas 确实和 Lucas 一点关系没有。)

(1)(1).对于模数 PP 根据唯一分解定理,我们可以把 PP 拆为几个质数相乘的形式。

P=i=1npikiP=\displaystyle\prod_{i=1}^{n} p_i^{k_i}

(2)(2).因为现在拆成的几个质数的乘积之间一定两两互质,根据中国剩余定理,可以列出下面的式子:

{xCnm(modp1k1)xCnm(modp2k2)xCnm(modpnkn)\begin{cases} x&\equiv C_n^m(\bmod\,p_1^{k_1})\\ x&\equiv C_n^m(\bmod\,p_2^{k_2})\\ &\vdots\\ x&\equiv C_n^m(\bmod\,p_n^{k_n})\\ \end{cases}

(3)(3).解出每一个方程。

(4)(4).合并中国剩余定理。

  1. 解释流程 (3)

相信大家最疑惑的一定是 (3)(3) 吧,我们随便拎出来一个式子:

Cnmmodpk=n!m!(nm)!modpkC_n^m\bmod p^k=\frac{n!}{m!(n-m)!}\bmod p^k

阶乘内可能含有 pp,无法求逆元怎么解决呢?

Answer :那就把 pp 提出来!

举个很经典的栗子

22!,p=3,k=2,pk=922!,p=3,k=2,p^k=9

22!(1×2×4×5×7×8)×(10×11×13×14×16×17)×(19×20×22)×(3×6×9×12×15×18×21)(mod32)(1×2×4×5×7×8)2×(19×20×22)×37(1×2×3×4×5×6×7)(mod32)\begin{aligned} 22! &\equiv(1\times 2\times 4\times 5\times 7\times 8)\\ &\times (10\times 11\times 13\times 14\times 16\times 17)\\ &\times (19\times 20\times 22)\\ &\times (3\times 6\times 9\times 12\times 15\times 18\times 21)(\bmod\,3^2)\\ &\equiv(1\times 2\times 4\times 5\times 7\times 8)^2\\ &\times (19\times 20\times 22)\\ &\times 3^7(1\times 2\times 3\times 4\times 5\times 6\times 7)(\bmod\,3^2)\\ \end{aligned}

我们可以发现这样一个规律:

可以将式子拆为四部分

  • 提出来的 px,x=npp^x,x={\lfloor\frac{n}{p}\rfloor}
  • 含有质因子为 pp 的数每个都提出一个 pp 后变成了 np!{\lfloor\frac{n}{p}\rfloor}!
  • 不含质因子但可以凑成以 pkp^k 为单位的 npk{\lfloor\frac{n}{p^k}\rfloor} 组数。
  • 剩下的数字。

化成一个恶心的式子:

n!=np!×pnp×(i=1ippki)npk×(i=pk×npk+1ipni)\begin{aligned} n!={\lfloor\frac{n}{p}\rfloor}!\times p^{\lfloor\frac{n}{p}\rfloor}\times ({\displaystyle\prod_{i=1\land i\nmid p}^{p^k}i})^{\lfloor\frac{n}{p^k}\rfloor}\times ({\displaystyle\prod_{i=p^k\times{\lfloor\frac{n}{p^k}\rfloor}+1\land i\nmid p}^{n}i}) \end{aligned}

我们发现 np!{\lfloor\frac{n}{p}\rfloor}! 可以继续递归求解

我们定义 f(n)f(n) 为提完所有 pp 以后阶乘之和,定义函数 g(n)g(n) 为从 n!n! 提出来的 pp 的次幂。同样可以递归求解。

f(x)=f(np)×(i=1ippki)npk×(i=pk×npk+1ipni)f(x)={f(\lfloor\frac{n}{p}\rfloor})\times({\displaystyle\prod_{i=1\land i\nmid p}^{p^k}i})^{\lfloor\frac{n}{p^k}\rfloor}\times({\displaystyle\prod_{i=p^k\times {\lfloor\frac{n}{p^k}\rfloor}+1\land i\nmid p}^{n}i}) g(n)=np+g(np)g(n)=\lfloor\frac{n}{p}\rfloor+g(\lfloor\frac{n}{p}\rfloor)

对每一个阶乘进行操作,就得到了这个式子:

n!pxm!py×(nm)!pz×pxyz(modpk)\frac{\frac{n!}{p^x}}{\frac{m!}{p^y}\times\frac{(n-m)!}{p^z}}\times p^{x-y-z}(\bmod\,p^k) f(n)f(m)f(nm)pg(n)g(nm)g(m)(modpk)\frac{f(n)}{f(m)f(n-m)}p^{g(n)-g(n-m)-g(m)}(\bmod\,p^k)

此时我们发现:我们已经从所有阶乘中提尽了 pp

gcd(pk,f(m))=1gcd(pk,f(nm))=1\because \gcd(p^k,f(m))=1 \land \gcd(p^k,f(n-m))=1

f(m),f(nm)\therefore f(m),f(n-m) 存在模 pkp^k 意义下的逆元。

其中 g(m)+g(nm)g(n)g(m)+g(n-m)\leqslant g(n) 一定成立。

简单说明一下,已知 n>mn\gt m,先将 n!n! 的前 mm 项消掉,剩下 nmn-m 项为 n×(n1)××(nm+1)n\times (n-1)\times …\times (n-m+1),所以这剩下的 nmn-m 项一定不小于 (nm)!(n-m)!,因此 g(m)+g(nm)g(n)g(m)+g(n-m)\leqslant g(n)

已经解决了最困难的一步,中国剩余定理等一些简单的东西可以参考前文。

成功了!

(引用完)


常用变换

注 : 由于篇幅限制,以下关于狄利克雷卷积和莫比乌斯反演的例题及解析都放在了 莫比乌斯反演总结 一文中,那是对这一部分内容的专题强化。

Dirichlet卷积

译名就是狄利克雷卷积

1.定义 : 对于两个数论函数 f(x),g(x)f(x),g(x) ,定义他们的卷积为

(fg)(n)=dnf(d)g(nd)(f*g)(n) = \sum_{d \mid n} f(d) \cdot g(\frac{n}{d})

2.性质:

  1. 交换律: fg=gff \ast g = g \ast f
  2. 结合律: (fg)h=f(gh) ( f \ast g ) \ast h = f \ast ( g \ast h )
  3. 分配律: f(g+h)=fg+fhf \ast ( g + h ) = f \ast g + f \ast h
  4. 单位元: ε\varepsilon 表示 [x=1][x=1] ,满足对任意函数 有 εf=f\varepsilon * f = f
  5. 对积性函数: 若 ff 为积性, gg 为积性,则 fgf*g 也为积性
  6. 对积性函数: 若 ff 为积性, fgf*g 也为积性,则 gg 为积性

3.常见卷积: 其中涉及到的数论函数详见数论函数总结

f1=dnf(d)f*1 = \sum_{d \mid n} f(d) idk1=σkid_k*1 = \sigma_k φ1=id\varphi * 1 = id μ1=ε\mu * 1 = \varepsilon idμ=φid * \mu = \varphi 11=τ1 * 1 = \tau

F=1fF = 1*f 则有

f=μFf = \mu * F

莫比乌斯反演

1.定义 : 对于以下求和函数 :

F(n)=dnf(d)F(n) = \sum_{d \mid n} f(d)

有 :

f(n)=dnμ(d)F(nd)f(n) = \sum_{d\mid n}\mu(d)F(\frac{n}{d})

2.莫比乌斯等式 :

ε(n)=dnμ(d)\varepsilon(n) = \sum_{d \mid n}\mu(d)

(即 μ1=ε\mu*1=\varepsilon ) 3.性质 : 若 F(n)F(n) 为积性函数,那么 f(n)f(n) 也为积性函数。

年少不知学姐(长)好,清北学堂泪两行