扩展欧几里得
来源:互联网 发布:php bindto 编辑:程序博客网 时间:2024/06/05 20:54
终于开了数论课了,,再也不是只贴模板了,稍微懂了点原理,先来一发链接
点我刷Exgcd
(里面的最后一题是孙子定理,也是模板题)
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
先贴几个最常见的模板:
最大公约数(辗转相除法)
#define ll long longll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
扩展欧几里得:求ax+by=gcd(a,b)中的x,y,其中d=gcd(a,b)
#define ll long longll exgcd(ll a,ll b,ll &x,ll &y){ll d;if (b==0){x=1;y=0;return a;}d=exgcd(b,a%b,y,x);y-=a/b*x;return d;}
孙子定理的模板:
其中a[]是各个除数,m[]是各个余数,n是同余式子的个数,学完同余再来解释模板原理
ll CRT(ll a[],ll m[],ll n){ll M=1,d,ret=0,i,x,y,Mi,temp;for(i=0;i<n;i++) M*=m[i];for(i=0;i<n;i++){Mi=M/m[i];d=Exgcd(m[i],Mi,x,y);temp=mod_mul(y,Mi,M);temp=mod_mul(temp,a[i],M);ret=(ret+temp)%M;}return (M+ret)%M;}
扩展欧几里得的最经典应用:
解决一次不定方程ax+by=c
(1)ax+by=c有解的充分必要条件是(a,b)=c
(2)利用公式的x0,y0得出一组特解,然后所有解为x=x0+b*k/gcd(a,b) y=y0-a*k/gcd(a,b)
(3)题中有时候是求出x或者y的最小正整数解,利用通式取余即可
下面是各个题的代码:
A:
ll x,y,n,m,l;ll a,b,g,mul;int main(){//input;while(scanf("%lld%lld%lld%lld%lld",&x,&y,&m,&n,&l)!=EOF){g=exgcd(m-n,-1*l,a,b);if ((y-x)%g){puts("Impossible");continue;}a*=(y-x)/g;mul=-1*l/g;//printf("%lld %lld\n",a,mul);a=(a%mul+mul)%mul;printf("%lld\n",a);}return 0;}
B:
int main(){//input;int i,j,k;pow2[0]=1;for(i=1;i<=35;i++) pow2[i]=2LL*pow2[i-1];//for(i=1;i<=35;i++) printf("%lld\n",pow2[i]);while(scanf("%lld%lld%lld%d",&a,&b,&c,&k)!=EOF){if (k==0) break;if (a==b){puts("0");continue;}g=exgcd(c,pow2[k],x,y);if ((b-a)%g){puts("FOREVER");continue;}//printf("%lld\n",g);x*=(b-a)/g;l=pow2[k]/g;//printf("%lld %lld\n",x,l);x=(x%l+l)%l;printf("%lld\n",x);//cout<<endl;}return 0;}
C:范围很小,直接根据题意for循环暴力即可
D:
ll a,b,g;ll l,r;ll x,y;int main(){//input;while(scanf("%I64d%I64d",&a,&b)!=EOF){g=exgcd(a,b,x,y);if (g!=1){puts("sorry");continue;}x=(x%b+b)%b;y=(1-a*x)/b;printf("%I64d %I64d\n",x,y);}return 0;}
E:
ll x,y,n,m,l;ll a,b,g,mul;int main(){//input;while(scanf("%lld%lld%lld%lld%lld",&x,&y,&m,&n,&l)!=EOF){g=exgcd(m-n,l,a,b);if ((y-x)%g){puts("Pat");continue;}a*=(y-x)/g;mul=-1*l/g;if (mul<0) mul=-1*mul;//printf("%lld %lld\n",a,mul);a=(a%mul+mul)%mul;printf("%lld\n",a);}return 0;}
F:
int main(){//input;while(scanf("%I64d%I64d%I64d",&a,&b,&m)!=EOF){if (a+b+m==0) break;tot=ansx=ansy=INF;tot*=99999999;g=exgcd(a,-1*b,x,y);x*=m/g;y*=m/g;l=b/g;if (l<0) l=-1*l;r=a/g;if (r<0) r=-1*r;x1=(x%l+l)%l;y=(y%r+r)%r;x2=(m+b*y)/a;for(x=x1;x<=x2;x+=l){y=(a*x-m)/b;if (y<0) continue;if (x+y<=ansx+ansy&&tot>=x*a+b*y){ansx=x;ansy=y;tot=x*a+b*y;}}g=exgcd(a,b,x,y);x*=m/g;y*=m/g;l=b/g;if (l<0) l=-1*l;r=a/g;if (r<0) r=-1*r;x1=(x%l+l)%l;y=(y%r+r)%r;x2=(m+b*y)/a;for(x=x1;x<=x2;x+=l){y=(m-a*x)/b;if (y<0) continue;if (x+y<=ansx+ansy&&tot>=x*a+b*y){ansx=x;ansy=y;tot=x*a+b*y;}}m=-1*m;g=exgcd(a,-1*b,x,y);x*=m/g;y*=m/g;l=b/g;if (l<0) l=-1*l;r=a/g;if (r<0) r=-1*r;x1=(x%l+l)%l;y=(y%r+r)%r;x2=(m+b*y)/a;for(x=x1;x<=x2;x+=l){y=(a*x-m)/b;if (y<0) continue;if (x+y<=ansx+ansy&&tot>=x*a+b*y){ansx=x;ansy=y;tot=x*a+b*y;}}printf("%I64d %I64d\n",ansx,ansy);}return 0;}
G:孙子定理模板应用没什么好说的。。。。
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
来几篇好的欧几里得的原理介绍的博客:
http://www.cnblogs.com/frog112111/archive/2012/08/19/2646012.html
http://www.acmerblog.com/extend-gcd-5610.html
看完这几个,刷完这几个题,模板弄下来,就基本没什么问题了。。这是最基本的内容了,学了同余等知识之后会有更多的结论
- 【欧几里得&扩展欧几里得】
- 欧几里得和扩展欧几里得
- 欧几里得 与 扩展欧几里得
- 欧几里得&扩展欧几里得
- 欧几里得和扩展欧几里得
- 欧几里得与扩展欧几里得
- 欧几里得和扩展欧几里得
- 欧几里得 与 扩展欧几里得
- 欧几里得 扩展欧几里得
- 欧几里得与扩展欧几里得
- 欧几里得 & 扩展欧几里得
- 欧几里得 与 扩展欧几里得
- 欧几里得和扩展欧几里得
- 欧几里得与扩展欧几里得
- 扩展欧几里得
- 扩展欧几里得
- 扩展欧几里得
- 扩展欧几里得
- Friendship (poj 1815 最小点割集+枚举)
- docker 数据管理
- 关于echarts动态显示数据报表相关问题
- [c++基础]typedef的作用域
- 【Linux】linux常用基本命令
- 扩展欧几里得
- 分享pdf转换成html的常用方法
- 使用Inno Setup打包Winform程序
- unity3d动画插件iTween
- android 录像和拍照功能
- 【学习日记】java多线程的知识点总结
- 从服务器中返回的时间字符串(或时间戳)的一些简单处理
- React 生命周期 笔记
- os引导程序boot从扇区拷贝os加载程序loader文件到内存(boot copy kernel to mem in the same method)