博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
poj 2891 扩展欧几里得迭代解同余方程组
阅读量:4710 次
发布时间:2019-06-10

本文共 2180 字,大约阅读时间需要 7 分钟。

Reference: http://www.cnblogs.com/ka200812/archive/2011/09/02/2164404.html

之前说过中国剩余定理传统解法的条件是m[i]两两互质,所以这题就不能用传统解法了= =

其实还有种方法:

 

先来看只有两个式子的方程组:

c≡b1 (mod a1)

c≡b2 (mod a2)

变形得c=a1*x+b1,c=a2*x+b2

a1*x-a2*y=b2-b1

可以用扩展欧几里得求出x和y,进而求出c

 

那么多个式子呢?可以两个两个的迭代求。

比如上面两个式子求完了,求出一个c,不妨先把它记作c1

c1满足上面两式,但对于所有的式子就不一定都满足了。

因此我们把一个新同余式加入方程组:c≡c1 (mod lcm(a1,a2))      //lcm为最小公倍数

然后依次往下迭代就行了。最后解出的c1就是最终解。

 

如何判断无解?

对于相邻的两行a1、a2、r1、r2,若 (r2-r1) mod (gcd(a1,a2))!=0说明无解

 

1 #include "iostream" 2 using namespace std; 3 __int64 a[1000]; 4 __int64 r[1000]; 5 int n; 6  7 __int64 extend_gcd(__int64 a,__int64 b,__int64 &x,__int64 &y){ 8     if (b==0){ 9         x=1;y=0;10         return a;11     }12     else{13         __int64 r=extend_gcd(b,a%b,y,x);14         y=y-x*(a/b);15         return r;16     }17 }18 19 __int64 gcd(__int64 a,__int64 b)20 {21     if (b==0) return a;22     return gcd(b,a%b);23 }24 25 __int64 lcm(__int64 a,__int64 b)26 {27     __int64 tm=gcd(a,b);28     if (tm==0)  return 0;29         else return (a*b/tm);30 }31 32 int main()33 {34     while (cin>>n)35     {36         for (int i=1;i<=n;i++)37             cin>>a[i]>>r[i];38 39         __int64 x,y,x1,c1;40         bool sol=true;41         for (int i=2;i<=n;i++)42         {43             __int64 a1=a[i-1],r1=r[i-1];44             __int64 a2=a[i],r2=r[i];45             __int64 tmp=gcd(a1,a2);46             if ((r2-r1)%tmp!=0)     sol=false;      //此处有个问题= =原来我是这样写的,WA了47             __int64 tm=extend_gcd(a1,a2,x,y);       //__int64 tm=extend_gcd(a1,-a2,x,y)48             x1=x*((r2-r1)/tm);                      //but the original equation is a1*x1-a2*x2=b2-b149             __int64 rq=a2/tm;                       //__int64 rq=-a2/tm     50             x1=(x1%rq+rq)%rq;                       //去掉a2的负号就A了,What a fuck!!!51                                                     //个人猜想是因为gcd(a,b)和gcd(a,-b)结果是一样的,52                                                     //而且此处需要的是非负解,结果就YY对了53             c1=a1*x1+r1;54             r[i]=c1;55             a[i]=lcm(a1,a2);56            // cout<
<<" "<
<

 

 至于负号那个地方有个题hdu 1576,和本题一个情况。把负号YY掉就对了= =

转载于:https://www.cnblogs.com/pdev/p/4069885.html

你可能感兴趣的文章
网络编程——第三篇 HTTP应用编程(下)
查看>>
进程管理(Process类)
查看>>
Android进阶篇-访问Https链接
查看>>
vi/vim编辑器
查看>>
黑马程序员——创建线程的两种方式
查看>>
Webservice之axis
查看>>
运输计划 洛谷P2680
查看>>
用 C# 计算 与 java 一致的unix时间戳 (长时间整形 如:1476956079961)
查看>>
找回任务栏得“显示桌面"图标
查看>>
mondrian 4.7 源码部署
查看>>
C#方法重载(overload)方法重写(override)隐藏(new)
查看>>
读书笔记1-编写可维护javascript代码
查看>>
Redis系列(三)—— 订阅/发布
查看>>
TDD:什么是桩(stub)和模拟(mock)?
查看>>
mysql_ my.cnf优化,安全配置和日志
查看>>
用了锚的时候,有的层被覆盖了。
查看>>
改变navigationbar的底部线条颜色
查看>>
算法入门经典第六章 例题6-9 天平
查看>>
extern的用法
查看>>
页面制作之开发工具
查看>>