逆元概念与模板
来源:互联网 发布:linux入门教程下载 编辑:程序博客网 时间:2024/06/16 00:56
如果两个数a和b,它们的乘积关于模m余1,我们称它们互为关于模m的数论倒数,⼀般形式为:a *b≡1(mod m)
还有⼀种形式是:对于正整数a和m,如果有a⋅x≡1(mod m),那么把这个同余⽅程中x的最⼩正整数解叫做a模m的逆元。
⽽我们要处理的⼀个⼤问题,就是如何去求逆元。
有的题⽬要求结果mod⼀个⼤质数,如果原本的结果中有除法,⽐如除以a,那就可以乘以a的逆元替代
【1】欧拉函数(费马⼩定理求逆元)
φ:N→N,n→φ(n)称为欧拉函数。对正整数n,欧拉函数的值是少于或等于n的数中与n互质的数的数⽬。
此外有欧拉定理:设a,m∈N,(a,m)=1(即a与m互质,最⼤公约数为1),则a^φ(m) ≡1(mod m),根据上边的性质我
们可以了解到,当m为质数时,欧拉函数的值为m-1。由此可得欧拉定理的⼀个特殊情况:
a^(m-1) ≡ 1(mod m)
(m为质数且a与m互质)
这就是⼤名⿍⿍的费马⼩定理。它是欧拉定理的⼀个特殊情况,我们观察这个式⼦,是不是有些似曾相识?
没错,将式⼦稍微变形,我们就可以得到
a*a^(m-2) ≡≡ 1(mod m)
也就是说,a关于m的逆元正是a^(m-2) 。于是,当a与m互质时,我们仅需使⽤快速幂求出a^(m-2) 的值即可。时间复
杂度O(√n)。要求:a和M互质,且M为质数。
代码:
///M 必须是质数const long long M = 1000000007;long long quickpow(long long a, long long b){ if (b < 0) { return 0; } long long ret = 1; a %= M; for (; b; b >>= 1, a = (a * a) % M) if (b & 1) { ret = (ret * a) % M; } return ret;}long long inv(long long a){ return quickpow(a, M - 2);}
【2】拓展欧⼏⾥得求逆元
拓展欧⼏⾥得算法可以求出ax+by=gcd(a,b)=d的整数解。那利⽤拓展欧⼏⾥得算法如何求乘法逆元呢?很简
单,我们对逆元的⽅程做⼀个简单的变换。
a⋅x≡1(mod m) <=> a*x+m*y=1
这⾥我们可以看到,当gcd(a,m)不为1的时候,⽅程是⽆解的。也就是说我们只需求出⼀个x的解,即可得出a
的逆元。但题⽬往往要求我们求最⼩的逆元,⾮常简单,直接让x%m即可。时间复杂度O(loga),要求互素
(m不⼀定要是素数)
代码:
///需要与M 互质const long long M = 1000000007;long long exgcd(long long a, long long b, long long &x, long long &y){ if (b == 0) { x = 1; y = 0; return a; } long long ans = exgcd(b, a % b, x, y); long long temp = x; x = y; y = temp - (a / b) * y; return ans;}long long inv(long long a){ long long x, y; long long t = exgcd(a, M, x, y); if (t != 1) { return -1; } return (x % M + M) % M;}
求ax ≡c(mod b)
typedef long long LL;LL e_gcd(LL a, LL b, LL &x, LL &y){ if (b == 0) { x = 1; y = 0; return a; } LL ans = e_gcd(b, a % b, x, y); LL temp = x; x = y; y = temp - a / b * y; return ans;}LL cal(LL a, LL b, LL c) ///求ax = c(mod b){ LL x, y; LL gcd = e_gcd(a, b, x, y); if (c % gcd != 0) { return -1; } x *= c / gcd; b /= gcd; if (b < 0) { b = -b; } LL ans = x % b; if (ans <= 0) { ans += b; } return ans;}
线性处理1~n的逆元
刚刚的两种⽅法全部要求a和m需要互质,但是有的题⽬两个数并不互质,这时我们有⼀种不需要a和m互质的算法
(但依然要求m为质数),线性处理法。
先说结论,这个算法可以去求1,2,3,…,N关于m的逆元(m为质数),x^(-1) ≡−(y/x)*(y mod x)^(-1) (mod y)
这样通过迭代我们可以得到从1~n的所有逆元,复杂度o(n).
证明过程略;代码如下:
const int mod = 1000000009;const int maxn = 10005;int inv[maxn];inv[1] = 1;for (int i = 2; i < 10000; i++){ inv[i] = inv[mod % i] * (mod - mod / i) % mod;}
- 逆元概念与模板
- 模板与友元
- 逆元模板总结
- (模板)逆元
- 逆元模板总结
- 乘法逆元模板
- 逆元模板
- 乘法逆元 模板
- 乘法逆元模板
- 数学模板-逆元
- [模板]乘法逆元
- 逆元模板
- 【模板】乘法逆元
- 逆元模板
- [模板]乘法逆元
- 类模板与模板类的概念
- 类模板与模板类的概念
- [模板] Lucas 逆元 快速幂模板
- 干货:产品经理怎么寻找软件开发项目
- 多态 2 polymorphism
- 关于./configure 出错的问题解决
- bzoj2243染色
- OpenCV Error: Insufficient memory
- 逆元概念与模板
- Day03jQuery事件绑定
- Error:Execution failed for task ':app:mergeDebugResources'. > Error: Some file crunching failed, see
- JAVA字符串操作
- 【dfs(深搜)模板】
- (十二)服务雪崩-熔断器
- keil ucosiii工程改为 iar工程
- 方法的调用以及用过super.的方式来调用。三种
- 调用activity.finish()和System.exit(0)的区别