于MOD如果是。 (a*b/c ) %MOD 不直接 / c 寻求,需要找到一些 inv 使 inv * c % MOD = 1 。
此 (a*b / c) % MOD = (a * b * inv) % MOD;
性质: 逆元是积性函数 存在 a*b = c ,那么 inv[c] = inv[a] * inv[b] % MOD;
1、 循环找解的方法
long long circleRun(long long n){
for(long long i = 1;i < MOD;i++)
if(i * n % MOD == 1)
return i;
return -1;
}
long long n;
int main(){
while(cin >> n){
cout << n << " 's inv is "<
2、费马小定理的解法 MOD 是质数才干用
利用 a ^ (p-1) % MOD === 1 , 那么它的逆元就是 a ^ (p-2)
#include
#include
#include
#include
using namespace std;
const int MOD = 1e9+7;
long long quickpow(long long base,long long n){
long long ans = 1;
while(n){
if(n%2 == 1) ans = ans * base % MOD;
n /= 2;
base = base * base % MOD;
}
return ans;
}
long long n;
int main(){
while(cin >> n){
cout << n << " 's inv is "<
3、利用欧几里德扩展来求 ,
欧几里德扩展 是用来解决 ax + by = gcd(a,b)这种等式。
这时候取 b = MOD, 你能够写成这样 ax = gcd(a,b) - by
推导出 a*x % MOD = gcd(a,b) %MOD
所以仅仅要 gcd(a,b) % MOD === 1时,就能够使用这条来求a的逆元
但用exgcd求得时候,inv可能是负数, 还须要进行例如以下操作
inv = (inv % MOD + MOD) % MOD;
long long exGcd(long long a, long long b, long long &x0, long long &y0) // a*x0 + b*y0 = gcd(a,b)
{
if(b==0)
{
x0 = 1;
y0 = 0;
return a;
}
long long r = exGcd(b, a % b, x0, y0);
long long t = x0;
x0 = y0;
y0 = t - a / b * y0;
return r;
}
long long n;
int main(){
while(cin >> n){
cout << n << " 's inv is "<
预处理1-n关于p的逆元:(n < p) , 由于 逆元是积性函数,所以仅仅要 p > n 成马上可。而不须要p必须为素数
如果已经预处理了1-i-1的逆元,j的逆元设为F[j]
令p = x * i –y ( 0 < y < i)
X* i = y (mod p)
X* F[y] * i = y * F[y] = 1(mod p)
所以i的逆元是F[i] = X* F[y]
这样就能够O(n)的时间预处理了。
參考链接
代码实现
const int N = 100005;
long long _inv[N];
void pre() {
_inv[0] = _inv[1] = 1;
for (int i = 2; i < N; i++) {
_inv[i] = ((MOD - MOD / i) * _inv[MOD % i]) % MOD;
}
}
long long n;
int main(){
pre();
while(cin >> n){
cout << _inv[n] << endl;
}
return 0;
}
4、 利用逆元函数是全然积性函数的性质
求全部质数的逆元就可以,预处理复杂度是O(n / logn * logn) = O(n)
这样的写法能够用 exgcd 来实现素数的logn 求逆,由于此时 a = p , MOD不管取何值(p除外) , 都有 gcd(p ,mod) = 1,适合通用情况。
之后再採取质因数分解的方法,就可以对随意一个 n 以 logn速度求出其逆元
只是。。ACM竞赛假使反演写代码,只要外观似不现实。
版权声明:本文博客原创文章。博客,未经同意,不得转载。