学习笔记:快速幂、逆元

学习笔记:快速幂、逆元

首先说一下取模的运算:

( a + b ) % m o d = ( a % m o d + b % m o d ) % m o d \left(a+b\right)\%mod=\left(a\%mod+b\%mod\right)\%mod
( a b ) % m o d = ( a % m o d b % m o d + m o d ) % m o d \left(a-b\right)\%mod=\left(a\%mod-b\%mod+mod\right)\%mod
( a b ) % m o d = ( a % m o d b % m o d ) % m o d \left(a*b\right)\%mod=\left(a\%mod*b\%mod\right)\%mod
但是:
( a / b ) % p = ( a % p / b % p ) % p \left(a/b\right)\%p=\left(a\%p/b\%p\right)\%p 是错误的!!!等式不成立。
例如: ( 6 / 2 ) % 2 = 1 \left(6/2\right)\%2=1 , ( 6 % 2 / 3 % 2 ) % 2 = 0 \left(6\%2/3\%2\right)\%2=0

切入正题:逆元

( a x ) % p = 1 \left(a∗x\right)\%p=1%mod , x x 就等于 1 a \frac{1}{a} 吗,不一定,因为这里还有条件呢: m o d mod p,所以在这个条件下 x x 叫做 a a 关于 p p 的逆元,比如: ( 2 3 ) % 5 = 1 (2∗3)\%5=1 ,那么 3 3 关于 5 5 的逆元就是 2 2 或者说 2 2 关于 5 5 的逆元就是 3 3 2 2 3 3 关于 5 5 互为逆元。

怎么求逆元呢?
费马小定理 a p 1 % p = 1 a^{p-1}\%p=1 ( a a p p 互质),
两边同时除 a a 得: a p 2 % p = 1 a a^{p-2}\%p=\frac{1}{a} ,大功告成, a a 关于 p p 的逆元就是 a p 2 % p a^{p-2}\%p ,记为 i n v ( a ) = a p 2 % p inv(a)=a^{p-2}\%p .

再回到刚开始的问题:如何求 ( a / b ) % p (a/b)\%p ,应用刚才的费马小定理即转换为 ( a i n v ( b ) ) % p (a*inv(b))\%p 再转化为 ( a % p i n v ( b ) % p ) % p (a\%p*inv(b)\%p)\%p ,就完全转换成好算的乘法了,所以就求出 i n v ( b ) = b p 2 % p inv(b)=b^{p-2}\%p 就可以算出结果了。

b p 2 b^{p-2} 就可以用快速幂解决,复杂度 O ( l o g n ) O(logn)
下面代码求 a b % m o d a^b\%mod

long long POW(long long a,long long b,long long mod)
{
    long long  base = a,ans=1;
    while(b)
    {
        if(b&1)
            ans=(ans*base)%mod;
        base=(base*base)%mod;
        b>>=1;
    }
    return ans;
}

再来个例题:hdu 1576 A/B

Problem Description

要求(A/B)%9973,但由于A很大,我们只给出n(n=A%9973)(我们给定的A必能被B整除,且gcd(B,9973) = 1)。

Input

数据的第一行是一个T,表示有T组数据。
每组数据有两个数n(0 <= n < 9973)和B(1 <= B <= 10^9)。

Output

对应每组数据输出(A/B)%9973。

Sample Input

2
1000 53
87 123456789

Sample Output

7922
6060

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<string>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<math.h>
using namespace std;
const int maxn=30010;
long long POW(long long a,long long b,long long mod)
{
    long long  base = a,ans=1;
    while(b)
    {
        if(b&1)
            ans=(ans*base)%mod;
        base=(base*base)%mod;
        b>>=1;
    }
    return ans;
}

int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        long long n,b;
        cin>>n>>b;//n=A%mod
        long long inv_b=POW(b,9973-2,9973);
        long long ans=(n*inv_b)%9973;
        printf("%lld\n",ans);
    }
    return 0;
}

发布了34 篇原创文章 · 获赞 7 · 访问量 1902

猜你喜欢

转载自blog.csdn.net/qq_43628761/article/details/90552179