数论2:同余,欧拉函数,逆元

数论2:同余,欧拉函数,逆元

同余

ab(modm)m|baab(modm),ab(modn)ab(mod[m,n])(k,m)=d,kaka(modm)aa(modmd)

公式三证明:

(k,m)=d,(kd,md)=1m|k(aa)md|kd(aa)mdkdmd|aa

公式三更一般的结论:

kaka(modm)aa(modm(m,k))

线性同余方程

axb(modm)ax+my=b

mx0(modm),axb(modm) 辗转相除

还有一种计算方法比较好理解(来自dls)

{100x0(mod100),(1)87x3(mod100),(2)

(1)(2),13x97(mod100),(3)(2)6×(3),9x21(mod100),(4)(3)(4),4x76(mod100)(4)2×(5)x69(mod100)

解线性同余方程板子:

// 求 a * x = b (mod m) 的解
ll modequ(ll a, ll b, ll m) {
    ll x, y;
    ll d = exgcd(a, m, x, y);
    if (b % d != 0) return -1;
    m /= d; a /= d; b /= d;
    x = x * b % m;
    if (x < 0) x += m;
    return x;
}

简化剩余系

所有的 n 满足 0<nm,(n,m)=1 构成了一个模 m 的简化剩余系。ϕ(m) 表示 n 的个数。

欧拉函数

ϕ(m)=mp|m(11p)

欧拉函数证明

ϕ(mn)=ϕ(m)ϕ(n)n=p1a1p2a2...pkakϕ(n)=ϕ(p1a1)...ϕ(pkak),ϕ(psas)=psasps(as1),(1)(1):1psaspsasps,2ps,...,psas1psas1psaspsas1ϕ(psas)=psaspsas1=psas(11ps)广:ϕ(n)=ϕ(p1a1)...ϕ(pkak)=p1a1...pkak(11p1)...(11pk)=ni=1k(11pi)

欧拉函数板子

ll phi (ll n) {
    ll ans = n;
    for (int i = 2; i*i <= n; i++) {
        if (n % i == 0) {
            ans = ans / i * (i - 1); //*(1-1/i)
            while (n % i == 0)  n /= i;
        }
    }
    if (n > 1)  ans = ans / n * (n - 1); //还剩下就再乘
    return ans;
}

欧拉定理

(a,m)=1,则 aϕ(m)1(modm)

m为素数时有 费马小定理:ap11(modp)

欧拉定理证明

1n 中与 n 互质的数为:p1,p2,...,pϕ(n),则有 ak1,ak2,...skϕ(n),二者在模n意义下等价(可以手搓几个例子模拟),

二式分别累乘,有 k1k2...kϕ(n)aϕ(n)k1k2...kϕ(n)(modn),即

i=1ϕ(n)kiaϕ(n)i=1ϕ(n)ki(modn)

根据同余公式三 kaka(modm)aa(modm(m,k))

则有

i=1ϕ(n)kiaϕ(n)i=1ϕ(n)ki(modn)1aϕ(n)(modn)

逆元

ax1(modm),称 xa 的逆元,记作 a1

快速幂求逆元模板

素数:

ap11(modp)aap21(modp)ap2a1(modp)

ll qmi(ll a, ll k, ll p) {
	ll ans = 1;
	while (k) {
		if (k & 1)	ans = ans * a % p;
		k >>= 1;
		a = a * a % p;
	}
	return ans;
}
//a mod p 的逆元为 qmi (a, p - 2, p)

扩展欧几里得求逆元模板

非素数:

aϕ(m)1(modm)aϕ(m)1a1(modm)

int d = exgcd(a, p, x, y);
if (d == 1) 	cout << (1ll * x + p) % p << endl;
else 	puts("impossible");

线性递推求逆元(1 - n)

inv[i] = (p - p / i) * inv[p % i] % p

证明(相当于等式变形):

p=(pmodi)+pi×ip,,0((pmodi)+pi×i)(modp)+,,pi((pmodi)×i1)(modp)i1pi×(pmodi)1(modp),pi1ppi×(pmodi)1(modp) 

板子:

inv[1] = 1;
for (int i = 2; i <= n; i++) {
    inv[i] = (p - p / i) * inv[p % i] % p;
}

前缀乘积求逆元

si=j=1iaj,ti=j=1iaj1ai1=si1ti

然后利用 s1s2...sntn...t2t1 求出每一项 si,ti,从而求得 ai

其中, sntn 这一步可以通过 exgcd 求逆元得出

利用前缀乘积,正反正 for 三遍即得

板子:

void solve () {
    s[0] = 1;
    for (int i = 1; i <= n; i++)    s[i] = s[i-1] * a[i] % p;
    ll x, y;
    exgcd (s[n], p, x, y);
    if (x < 0)  x += p;
    t[n] = x;

    for (int i = n; i >= 1; i--)    t[i-1] = t[i] * a[i] % p;
    for (int i = 1; i <= n; i++) {
        ll v = s[i-1] * t[i] % p;
        ans ^= v;
    }
    cout << ans;
}

Reference

求逆元的三种方法:https://zhuanlan.zhihu.com/p/100587745

习题

欧拉函数模板题 http://oj.daimayuan.top/course/12/problem/489

求逆元1 http://oj.daimayuan.top/course/12/problem/490

求逆元2 http://oj.daimayuan.top/course/12/problem/491

posted @   Sakana~  阅读(147)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示