zoukankan      html  css  js  c++  java
  • 逆元方法


    于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 "<<endl;
    		cout << circleRun(n) << endl;
    	}	
    	return 0;
    }

    2、费马小定理的解法  MOD 是质数才干用

    利用   a ^ (p-1) % MOD === 1 , 那么它的逆元就是     a ^ (p-2)

    #include<stdio.h>
    #include<string.h>
    #include<iostream>
    #include<cmath>
    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 "<<endl;
    		//cout << circleRun(n) << endl;
    		cout << " a ^ (p-2) % MOD "<< endl;
    		cout << quickpow(n, MOD-2) << endl;
    		
    	}	
    	return 0;
    }

    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 "<<endl;
    		//cout << circleRun(n) << endl;
    		cout << " a ^ (p-2) % MOD "<< endl;
    		cout << quickpow(n, MOD-2) << endl;
    		
    		cout << " ax + by = gcd(a,b) " << endl;
    		long long inv,y0;
    		exGcd(n ,MOD,inv,y0);
    		inv = (inv % MOD + MOD) % MOD;
    		cout << inv << endl;
    	}	
    	return 0;
    }


    4、利用某奇妙推导。。 O(n)求出 1---- n 的全部逆元。

     

    预处理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竞赛假使反演写代码,只要外观似不现实。


    版权声明:本文博客原创文章。博客,未经同意,不得转载。

  • 相关阅读:
    矩阵距离
    CF409D Big Data
    AT2685 i18n
    P3366 【模板】最小生成树
    P3367 【模板】并查集
    ISBN(洛谷P1055)
    关于数组
    0021---一元一次方程
    0020---求圆锥体积
    0019---求圆台的体积
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/4709916.html
Copyright © 2011-2022 走看看