数论相关:同余方程与同余方程组的解法
来源:互联网 发布:阿里云香港b区速度 编辑:程序博客网 时间:2024/04/29 13:53
同余方程
形如a*x≡b(mod n)的式子称为线性同余方程。对于这样的式子有解的充要条件是gcd(a,n)|b.
于是扩展gcd求解
将原方程化为一次不定方程 a*y+n*y=b.
利用扩展欧几里得算法求解不定方程a * x + n* y = b的整数解的求解全过程,步骤如下:
1、先计算Gcd(a,n),若n不能被Gcd(a,n)整除,则方程无整数解;否则,在方程两边同时除以b/gcd(a,n),得到新的不定方程a’* x + n’* y = gcd(a,n).
2、利用扩展欧几里德算法求出方程a’* x + n’* y = 1的一组整数解x0,y0,则gcd(a,n)* x0,gcd(a,n)* y0是方程a’* x + n’ * y = gcd(a,n)的一组整数解;
3、根据数论中的相关定理,记k=b/gcd(a,n),可得方程a* x + n * y = b的所有整数解为:
x = k*x0 + n/gcd(a,n)* t y =k* y0 –n/gcd(a,n)* t (t=0,1,2,……)
调整得到正整数解
注意因为解有多个,而我们要求最优解,所以(x+=n/gcd(a,n)%(n/gcd(a,n));
青蛙的约会
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <cstdlib>#include <cmath>using namespace std;long long init(){ long long rv=0,fh=1; char c=getchar(); while(c<'0'||c>'9'){ if(c=='-') fh=-1; c=getchar(); } while(c>='0'&&c<='9'){ rv=(rv<<1)+(rv<<3)+c-'0'; c=getchar(); } return fh*rv;}long long x,y,m,n,l;long long exgcd(long long a,long long b,long long &x,long long &y){ if(b==0){ x=1;y=0;return a; } long long t=exgcd(b,a%b,y,x); y-=(a/b)*x; return t;}int main(){ freopen("in.txt","r",stdin); x=init();y=init();m=init();n=init();l=init(); if(m - n< 0) swap(m, n), swap(x, y); long long a=0,b=0; long long t=exgcd(m-n,l,a,b); if(n==m||(x-y)%t!=0){ printf("Impossible"); return 0; } (a*=(y-x)/t)%=(l/t); (a+=l)%=(l/t);//以保证最优解 cout<<a; fclose(stdin); return 0;}
exgcd可以用来求逆元
a*x≡1(mod n) 已知a,n求x
因为n是个素数,所以gcd(a,n)==1;
原方程可化为 a*x≡gcd(a,n)(mod n)
用exgcd求解即可。
同余方程组
x%p1 = b1
x%p2 = b2
x%p3 = b3
x%p4 = b4
求x的最小正整数解
小范围数据直接枚举
对于模数互质的情况,使用中国剩余定理(CRT)
令m=p1p2p3…pn
构造出
//ni(k,p)是k在模p意义下逆元
x = (m/p1*ni(m/p1, p1)*a1 + …) c% m
CRT求解同余方程组
#include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>using namespace std;long long a1,a2,a3,a4,b1,b2,b3,b4;long long m;long long exgcd(long long a,long long b,long long &x,long long &y){ if(!b){ x=1;y=0; return a; } long long t=exgcd(b,a%b,y,x); y-=a/b*x; return t;}long long ni(long long a,long long b){ long long x=0,y=0; long long t=exgcd(a,b,x,y); if(t!=1) return -1; else return((x+b)%b);}int main(){ freopen("in.txt","r",stdin); cin>>a1>>b1>>a2>>b2>>a3>>b3>>a4>>b4; m=a1*a2*a3*a4; cout<<(m/a1*ni(m/a1,a1)*b1+m/a2*ni(m/a2,a2)*b2+m/a3*ni(m/a3,a3)*b3+m/a4*ni(m/a4,a4)*b4)%m; fclose(stdin); return 0;}
对于一般情况采用exgcd两两合并,
x+a1k1=b1
x+k2a2=b2
a1k1-a2k2=b1-b2
t=exgcd(a1,-a2,k1,k2) 实际上-a2可以写作a2
合并:k1=(k1*(b1-b2)/t)%a2; //此处是模a2,因为可以看成是模a2意义下的同余方程
b1-=a1*k1 //b1就是原式中的x
a1=a1/t*a2 //把a1变成lcm(a1,a2)
b1%=a1 //把b1调整至新式子的B
此时就把两个式子合并为了一个,待所有的都合并完后,结果就是b1调整好的最小正整数(b1+=a1)%=a1
#include <iostream>#include <cstdio>#include <cstring>#include <cmath>#include <algorithm>#include <cstdlib>#define LL long long using namespace std;LL init(){ LL rv=0,fh=1; char c=getchar(); while(c<'0'||c>'9'){ if(c=='-') fh=-1; c=getchar(); } while(c>='0'&&c<='9'){ rv=(rv<<1)+(rv<<3)+c-'0'; c=getchar(); } return rv*fh;}LL a,b,a1,b1;LL exgcd(LL a,LL b,LL &x,LL &y){ if(!b){ x=1;y=0;return a; } LL t=exgcd(b,a%b,y,x); y-=a/b*x; return t;}int main(){ freopen("in.txt","r",stdin); a=init();b=init(); for(int i=1;i<=3;i++){ a1=init();b1=init(); LL x=0,y=0; LL t=exgcd(a,a1,x,y); x=(x*(b-b1)/t)%a1; b-=a*x; a=a/t*a1; b%=a; } (b+=a)%=a; cout<<b; fclose(stdin); return 0;}
求逆元
a*x≡1(mod n)
逆元存在的充要条件是gcd(a,n)==1;
一般采用exgcd求逆元,若p是质数,也可使用费马小定理,快速幂
- 数论相关:同余方程与同余方程组的解法
- poj2115 数论 同余方程
- 一元线性同余方程&&一元线性同余方程组
- 一元线性同余方程组【数论
- 数论 算法 不定方程 欧几里得 同余定理 相关知识
- 同余方程组问题
- 同余方程组求解
- 数论,扩展欧几里德算法,同余方程
- NOIP2012 同余方程的两种解法
- 线性同余方程及其特殊情况的求解法
- 二次同余方程模合数的一般解法
- POJ1061_青蛙的约会(数论/同余方程)
- 青蛙的约会 ---- 同余方程(数论)
- 数论的同余定理
- 线性同余方程
- 解同余方程
- 线性同余方程
- 线性同余方程
- CentOS 7.X配置连接网络
- 大数据、人工智能、机器人,有什么血缘关系?
- Linux实际内存使用计算
- 05 rest-framework之用户认证和权限管理
- jqGrid简单使用、json格式和jsonReader介绍
- 数论相关:同余方程与同余方程组的解法
- POJ1163—三角形矩阵最大路径
- 整合spring cloud云服务架构
- UBIFS文件系统使用
- Unity 游戏框架搭建 (五) 简易消息机制
- html从入门到放弃(2)-入门标签:带输入格式的段落、文字方向和块引用(2)
- S5PV210开发 -- 交叉编译器
- for语句的3道面试题
- 三级联动省市区城市选择器v2.1.0新版本发布