求解逆元

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sunshiness_s/article/details/79831752

首先说下逆元的意思
若存在ax1(mod p),那么可以成 x 为 a 的逆
模 p 意义下,一个数 a 如果有逆元 x ,那么除以 a 相当于乘以 x
那么逆元可以用来做什么呢
有的题目中想要求abM,但是..分数模M意义就有了不同,那么就可以通过逆元来计算

下面说几种求逆元的方法
1. 扩展欧几里得
ax1(mod p) 相当于ax=1+py,也就是axpy=1(mod p)
注:这种算法要求 gcd(a,p)=1,否则则没有逆元

例如 hdu1576

#include <cstdio>
#define M 9973
int exgcd(int a,int b,int &x,int &y){
    if(!b){x=1,y=0;return a;}
    int c=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return c;
}
int main(){
    int T,a,b,x,y;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&a,&b);
        exgcd(b,M,x,y);
        x=(x*a%M+M)%M;
        printf("%d\n",x);
    }
    return 0; 
} 

2.费马小定理
费马小定理是说 ap11(mod p) p为素数,gcd(a,p)=1
因此 a×ap21(mod p)
ap2也就是a得逆元
ap2就可以用快速幂等方法啦

例如 hdu1576

#include <cstdio>
#define M 9973
int T,a,b;
int pow(int x,int y){
    int t=1;
    while(y){
        if(y&1) t=t*x%M;
        x=x*x%M;y>>=1;
    }return t;
}
int main(){
    freopen("hdu1576.in","r",stdin);
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&a,&b);
        b=b%M;
        printf("%d\n",a*pow(b,M-2)%M);
    }
    return 0; 
} 

3.逆元打表(递推)
我们定义inv[i]为模M(M为质数) 意义下i的逆元,那么inv[i]=(MMi)×inv[M%i]%M
怎么证明呢
我们假设

t=Mik=modi

那么
k+ti0(modM)

kti(modM)

左右同除ik
1itk(modM)

inv[i]=t×inv[k]

因此
inv[i]=(MMi)×inv[Mmodi]modM

代码如下

inv[1] = 1;
for(i=2;i<M;++i) inv[i]=(M-M/i)*inv[M%i]%M;

4.欧拉定理
欧拉定理是说:若 a 与 n 互质,则aϕ(n)1(mod n)
由此可以看出..欧拉定理相当于费马小定理的推广吧(因为ϕ(n)=n1嘛)

ϕ(n)就是欧拉函数,表示不超过n,且与n互质的正整数的个数
例如:

n 1 2 3 4 5 6 7 8 9 10
ϕ(n) 1 1 2 2 4 2 6 4 6 4

有两个引理

  • 引理1
    • (1)如果n为素数,则ϕ(n)=n1
    • (2)如果n为素数p的m次方,则ϕ(n)=ϕ(pm)=(p1)×pm1
    • (3)如果n为任意两个互质的数a、b的积,则ϕ(n)=ϕ(a×b)=ϕ(a)×ϕ(b)
  • 引理2
    • n=p1a1×p2a2×p2a2×pkak(其中pi为质数),则ϕ(n)=n×(11p1)×(11p2)×(11pk)

当然还要许多结论qaq,这里就先说一个跟求欧拉函数有关的吧~
若p为素数,p为x约数,则

ϕ(px)=ϕ(x)p

若p不为x约数,则
ϕ(px)=ϕ(x)ϕ(p)=ϕ(x)(p1)
;
证明在这里就先不说了…(有时间再填坑吧~)

例题:hdu2824
求一段区间欧拉函数值

#include <cstdio>
#include <cstring>
#define N 3300000
int prime[N],isprime[N],phi[N],tot=0,a,b;
void euler(){
    memset(isprime,true,sizeof(prime));isprime[0]=isprime[1]=false;
    for(int i=2;i<=3000000;i++){
        if(isprime[i]) prime[++tot]=i,phi[i]=i-1;
        for(int j=1;i*prime[j]<=3000000;j++){
            int k=i*prime[j];
            isprime[k]=false;
            if(i%prime[j]==0){
                phi[k]=phi[i]*prime[j];
                break;
            }else phi[k]=phi[i]*(prime[j]-1);
        }
    }
}
int main(){
    euler();
    while(scanf("%d%d",&a,&b)>0){
        long long ans=0;
        for(int i=a;i<=b;i++) ans+=(long long)phi[i];
        printf("%lld\n",ans);
    } 
    return 0;
} 

5.特殊情况
条件b|a

abd(modp)

那么
ab=d+px

a=bd+bpx

abd(modbp)

a(modbp)b=d

这个看起来就很有趣了~ 不过..我还没有试过【捂脸】

阅读更多
换一批

没有更多推荐了,返回首页