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;
}