快速幂,快速幂求逆元

快速幂

acwing875.快速幂

可以快速求在O(log \(k\))复杂度下出 \(a^{k}\)mod \(p\) 的结果($1\leq a,p,k\leq 10^{9} $)

如果是n组数据,时间复杂度就是O(\(n * log k\))

基本思路

1.先预处理出来\(a^{2^{0}},a^{2^{1}},...,a^{2^{logk}}\)这k个数
2.将\(a^{k}\)\(a^{2^{0}},a^{2^{1}},...,a^{2^{logk}}\)这k个数来组合,即组合出\(a^{k}\) = \(a^{2^{x1}}*a^{2^{x2}}*...*a^{2^{xt}}\) = \(a^{2^{x1}+2^{x2}+...+2^{xt}}\)

ps: 为什么 \(k\) 可以用 \({2^{0}},{2^{1}},{2^{2}},...{2^{logk}}\) 中的数凑出来?
答: \(2^{{log_{2}}k} = k\) 所以一定可以凑出k

如何组合出\(a^{k}\)

将k看成二进制形式

如果最后一位为1则乘上当前位的权,并将权乘个a倍变成下一个位的权


例子:凑\(a^{5}\),5写为二进制为101

1.最后一位为1,此位权为\(a^{2^{0}}\),res = 1*\(a^{2^{0}}\),将权改成a倍变成下一位权\(a^{2^{1}}\),将二进制数101最后一位去掉变成二进制数10

2.最后一位为0,此位权为\(a^{2^{1}}\),res = 1*\(a^{2^{0}}\)不变,将权改成a倍变成下一位权\(a^{2^{2}}\),将二进制数10最后一位去掉变成二进制数1

3.最后一位为1,此位权为\(a^{2^{2}}\),res = 1*\(a^{2^{0}} * a^{2^{2}}\),将权改成a倍变成下一位权\(a^{2^{3}}\),将二进制数10最后一位去掉变成二进制数1

所以 res = \(a^5\) 就可以计算出来


所以步骤就是,只要b不为0
	如果b的二进制最后一位为1则res乘上当前权
	权变为原来平方
	b最后一位去掉

注意

凡是中间结果可能会溢出的地方,都要特殊处理:

1.快速幂的结果都要开long long,快速幂计算过程中res和权要开long long

2.可能溢出的地方(res、权)都要取模

代码

#include<iostream>

using namespace std;

typedef long long LL;

LL qmi(int a,int b,int p)
{
    LL res = 1 % p;
    while(b)
    {
        if(b & 1) res = res * a % p;
        a = (LL)a * a % p; // 这里要开LL
        b >>= 1;
    }
    return res;
}

int main()
{
    int n;
    scanf("%d",&n);
    
    while(n --)
    {
        int a,b,p;
        scanf("%d%d%d",&a,&b,&p);
        printf("%lld\n",qmi(a,b,p));
    }
    
    return 0;
}

快速幂求逆元

acwing876.快速幂求逆元

欧拉定理与费马小定理

欧拉定理:若\(a\)\(p\)互质,则\(a^{\varphi (p)}\equiv1\: mod (p)\)

费马小定理:若\(p\)为质数,则\(a^{p-1}\equiv1\: mod (p)\)

互质:如果两个数的公约数只有1,则这两个数互质

思路


此题给了p一定为质数,就用欧拉定理推论费马小定理来求逆元即可

\(a / b ≡ a * x(mod\: m)\),则称 x 为 b 的模 m 乘法逆元
两边同乘b得 \(a ≡ a * b * x(mod\: m)\)
\(1 ≡b * x(mod\: \: m)\)
\(b * x ≡ 1(mod\: m)\)

若b和m互质 是 存在(b模m的)乘法逆元x 的充要条件。
由费马小定理得 \(b^{m-1} ≡ b * x ≡ 1(mod\: m)\),因此 $x = b^{m-2} $


题中给定a、p其中p为质数,求a模p的乘法逆元。
分为两种情况:
1.如果a和p互质,有\(a^{p-1} ≡ 1 mod(p)\),所以答案为 \(a^{p-2}\)
2.如果a和p不互质,不存在逆元

那么求\(a^{p-2}\)使用快速幂即可

代码

#include<iostream>

using namespace std;

typedef long long LL;

LL pmi(int a,int k,int p) // a^k mod p
{
    LL res = 1 ;
    while(k)
    {
        if(k&1) res = res * a % p;
        a = (LL) a * a % p;
        k >>= 1;
    }
    
    return res;
}

int main()
{
    int n;
    scanf("%d",&n);
    while(n --)
    {
        int a,p;
        scanf("%d%d",&a,&p);
        if(a % p == 0) puts("impossible"); // p为质数,a<p必然互质,a>p只要不是p的倍数必然互质
        else printf("%lld\n",pmi(a,p-2,p));
    }
    
    return 0;
}
posted @ 2022-08-16 12:18  r涤生  阅读(53)  评论(0编辑  收藏  举报