求解逆元

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

下面说几种求逆元的方法
1. 扩展欧几里得
ax1(modax≡1(mod p)p) 相当于ax=1+pyax=1+py,也就是axpy=1(modax−py=1(mod p)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(modap−1≡1(mod p)p) p(p为素数,gcd(a,p)=1gcd(a,p)=1)
因此 a×ap21(moda×ap−2≡1(mod p)p)
ap2ap−2也就是a得逆元
ap2ap−2就可以用快速幂等方法啦

例如 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]inv[i]为模MM(M为质数) 意义下i的逆元,那么inv[i]=(MMi)×inv[Minv[i]=(M−Mi)×inv[M%i]i]%MM
怎么证明呢
我们假设

t=Mik=modi

那么

k+ti0(modM)k+t∗i≡0(modM)

kti(modM)⇒k≡−t∗i(modM)

左右同除iki∗k
1itk(modM)⇒1i≡−tk(modM)

inv[i]=t×inv[k]⇒inv[i]=−t×inv[k]

因此
inv[i]=(MMi)×inv[Mmodi]modMinv[i]=(M−Mi)×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(modaϕ(n)≡1(mod n)n)
由此可以看出..欧拉定理相当于费马小定理的推广吧(因为ϕ(n)=n1ϕ(n)=n−1嘛)

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

n12345678910
ϕ(n)ϕ(n)1122426464

有两个引理

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

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

ϕ(px)=ϕ(x)pϕ(p∗x)=ϕ(x)∗p

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

例题: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(modp)

那么
ab=d+pxab=d+px

a=bd+bpx⇒a=bd+bpx

abd(modbp)⇒a≡bd(modbp)

a(modbp)b=d⇒a(mod−bp)b=d

这个看起来就很有趣了~ 不过..我还没有试过【捂脸】
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值