同余方程

exgcd模板:

int exgcd(int a,int b,int &x,int &y){
    if(b==0){
        x=1,y=0;
        return a;
    }else{
        int d=exgcd(b,a%b,y,x);
        y-=a/b*x;
        return d;
    }
}
乘法逆元:

逆元:A是B模C的逆元,是指 A * B = 1 mod C,即 A 与 B 的乘积模 C 的余数为 1。可表示为 A = B-1mod C。

计算:ax≡1(mod m),即ax+my=1,若gcd(a,m)!=1,则无解,由扩展欧几里得可知x=x0+km,k为任意整数,只需要求出一个k,使得x=x0+km为最小正整数,最小的时候才满足在0-(m-1)之间,这时候的x就是我们要求的逆元

最小正整数解的计算:ax≡1(mod m),计算出一组x0,则最小正整数解为(x0%m+m)%m

线性同余方程:

一元线性同余方程:ax≡c(mod b)
定理:设d=gcd(a,m),若d不能整除c则无解(即ax+by=c无解),否则式子有d个模b不同余的解
解集的计算:ax+by=c,设gcd(a,b)=d用扩展欧几里得算法求出ax+by=d的一组特解(x1,y1),设k=c/d,则ax+by=c的解集为x=kx1+t(b/d),y=ky1–t(a/d) ,t为任意整数。其中,x模b不同余的解共有 d 个:x=kx1+t(b/d),t=0, 1, …, d-1
最小非负解的计算:设 s=b/d,x的最小非负解为((kx1)%s+s)%s

模的逆:ax≡1(mod m)称为a模m的逆
设a模m的逆为k,即ak≡1(mod m)
对于ax≡b(mod m),两边同时乘k,得到akx≡bk(mod m),因为ak%m=1
所以式子变为x≡bk(mod m),即x和bk同余,所以答案就是bk

定理:设p是素数,正整数a是a自身模p的逆,则a≡1(mod p)或者a≡-1(mod p)
证明:若a≡1(mod p)或者a≡-1(mod p),则a2=1(mod p),所以a是自身模p的逆。反过来,p|(a2-1)。 又因为a2-1=(a-1)(a+1),所以p|(a-1)或者p|(a+1)。
综上可得a≡1(mod p)或者a≡-1(mod p)

费马小定理:

若p是素数,且gcd(a,p)=1,那么ap-1≡1(mod p)
因此a*ap-2≡1(mod p),则ap-2是a模p的一个逆,ap-2可用快速幂计算

线性同余方程组:

1.有两个以上的不同模的一元线性同余方程
2.变元数大于1,方程数大于1,但是方程的模相同

举例:
1.有两个以上的不同模的一元线性同余方程:
x≡a1(mod m1)
x≡a2(mod m2)
可用中国剩余定理解决

2.变元数大于1,方程数大于1,但是方程的模相同
x+y≡a1(mod m)
x-y≡a2(mod m)
可用高斯消元解决


P1082 同余方程

题意:

给a,b
求关于x的同余方程ax≡1(modb) 的最小正整数解。
输入保证有解

思路:

exgcd求同余方程最小整数阶模板题

code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
int exgcd(int a,int b,int &x,int &y){
    if(!b){
        x=1,y=0;
        return a;
    }else{
        int d=exgcd(b,a%b,y,x);
        y-=a/b*x;
        return d;
    }
}
signed main(){
    int a,b;
    cin>>a>>b;
    int x,y;
    exgcd(a,b,x,y);
    cout<<(x%b+b)%b<<endl;
    return 0;
}

POJ2115 C Looooops

题意:

给a,b,c,k
求a+cx≡b(mod 2k)的最小正整数解

思路:

a+cx≡b(mod 2k)
即cx≡(b-a) (mod 2k)
cx+2ky=(b-a)
其实是求解一元线性同余方程的模板题

code:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
#define int long long
int exgcd(int a,int b,int &x,int &y){
    if(!b){
        x=1,y=0;
        return a;
    }else{
        int d=exgcd(b,a%b,y,x);
        y-=a/b*x;
        return d;
    }
}
signed main(){
    int A,B,C,k;
    while(cin>>A>>B>>C>>k){
        if(!(A+B+C+k))break;
        int a=C;
        int b=1;
        for(int i=1;i<=k;i++){
            b<<=1;
        }
        int c=B-A;
        int x,y;
        int d=exgcd(a,b,x,y);
        if(c%d!=0){//无解
            cout<<"FOREVER"<<endl;
        }else{
            int k=c/d;
            int s=b/d;
            cout<<((k*x)%s+s)%s<<endl;
        }
    }
    return 0;
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值