Strange Way to Express Integers(扩展欧几里得+乘法逆元+中国剩余定理求解非互质的模线性方程组)
2015-08-25 14:42
856 查看
Link:http://poj.org/problem?id=2891
题意:给出模线性方程组的每个式子的除数和余数,求最小满足这些式子的被除数是多少。若无解则输出-1。
编程思想:扩展欧几里得+乘法逆元+中国剩余定理。
AC code1(递归版):
AC code2(非递归版):
Strange Way to Express Integers
Elina is reading a book written by Rujia Liu, which introduces a strange way to express non-negative integers. The way is described as following: Choose k different positive integers a1, a2, …, ak. For some non-negative m, divide it by every ai (1 ≤ i ≤ k) to find the remainder ri. If a1, a2, …, ak are properly chosen, m can be determined, then the pairs (ai, ri) can be used to express m. “It is easy to calculate the pairs from m, ” said Elina. “But how can I find m from the pairs?” Since Elina is new to programming, this problem is too difficult for her. Can you help her? Input The input contains multiple test cases. Each test cases consists of some lines. Line 1: Contains the integer k. Lines 2 ~ k + 1: Each contains a pair of integers ai, ri (1 ≤ i ≤ k). Output Output the non-negative integer m on a separate line for each test case. If there are multiple possible values, output the smallest one. If there are no possible values, output -1. Sample Input 2 8 7 11 9 Sample Output 31 Hint All integers in the input and the output are non-negative and can be represented by 64-bit integral types. Source POJ Monthly--2006.07.30, Static |
编程思想:扩展欧几里得+乘法逆元+中国剩余定理。
AC code1(递归版):
/** 中国剩余定理(不互质) */ #include <iostream> #include <cstdio> #include <cstring> using namespace std; typedef __int64 int64; int64 Mod; int64 gcd(int64 a, int64 b) { if(b==0) return a; return gcd(b,a%b); } int64 Extend_Euclid(int64 a, int64 b, int64&x, int64& y)//ax+by=gcd(a,b) { if(b==0) { x=1,y=0; return a; } int64 d = Extend_Euclid(b,a%b,x,y); int64 t = x; x = y; y = t - a/b*y; return d; } //a在模n乘法下的逆元,没有则返回-1 int64 inv(int64 a, int64 n) { int64 x,y; int64 t = Extend_Euclid(a,n,x,y); if(t != 1) return -1; return (x%n+n)%n; } //将两个方程合并为一个 bool merge(int64 a1, int64 n1, int64 a2, int64 n2, int64& a3, int64& n3) { int64 d = gcd(n1,n2); int64 c = a2-a1; if(c%d) return false; c = (c%n2+n2)%n2; c /= d; n1 /= d; n2 /= d; c *= inv(n1,n2); c %= n2; c *= n1*d; c += a1; n3 = n1*n2*d; a3 = (c%n3+n3)%n3; return true; } //求模线性方程组x=ai(mod ni),ni可以不互质 int64 China_Reminder2(int len, int64* a, int64* n)//len为模方程的式子总数,a[i]、n[i]分别表示第i个式子的余数、除数 { int64 a1=a[0],n1=n[0]; int64 a2,n2; for(int i = 1; i < len; i++) { int64 aa,nn; a2 = a[i],n2=n[i]; if(!merge(a1,n1,a2,n2,aa,nn)) return -1;//无解输出-1 a1 = aa; n1 = nn; } Mod = n1; return (a1%n1+n1)%n1; } int64 a[1000],b[1000]; int main() { int i; int k; while(scanf("%d",&k)!=EOF) { for(i = 0; i < k; i++) scanf("%I64d %I64d",&a[i],&b[i]); printf("%I64d\n",China_Reminder2(k,b,a)); } return 0; }
AC code2(非递归版):
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <vector> #include <string> #include <queue> #include <stack> #include <algorithm> #define PI acos(-1.0) #define LINF 1000000000000000000LL #define eps 1e-8 #define LL long long #define MAXN 100010 #define MOD 1000000007 using namespace std; const int INF=0x3f3f3f3f; LL Mod; LL gcd(LL a, LL b) { if(b==0) return a; return gcd(b,a%b); } LL exgcd(LL A,LL &x,LL B,LL &y) { LL x1,y1,x0,y0; x0=1;y0=0; x1=0;y1=1; LL r=(A%B+B)%B; LL q=(A-r)/B; x=0;y=1; while(r) { x=x0-q*x1; y=y0-q*y1; x0=x1; y0=y1; x1=x;y1=y; A=B;B=r;r=A%B; q=(A-r)/B; } return B; } LL ABS(LL x) { return x>=0?x:-x; } /*接下来介绍乘法逆元: 若m≥1,gcd(a,m)=1,则存在c使得 ca≡1(mod m) 我们把c称为是a对模m的逆,记为 a-1(mod m)或a-1 可以用扩展欧几里德算法求a-1 应用: 求(a/b)%c时,若a为大整数时可以写成 ((a%c)*((b-1)%c))%c,注意:这里(b-1)是b%c的乘法逆元,不是b减 1!!! 还可以使用扩展欧几里德算法求乘法逆元:*/ //a在模n乘法下的逆元,没有则返回-1(a * b % n == 1,已知a,n,求b就是求a模n的乘法逆元) LL inv(LL a, LL n) { LL x,y; //int64 t = Extend_Euclid(a,n,x,y); /******************************************* 扩展欧几里得算法求乘法逆元 调用:exgcd(a,x,b,y); 则: x为a模b的乘法逆元,y为b模a的乘法逆元 ********************************************/ LL t = exgcd(a,x,n,y); if(t != 1) return -1; return (x%n+n)%n; } //将两个方程合并为一个 bool merge(LL a1, LL n1, LL a2, LL n2, LL& a3, LL& n3) { LL d = gcd(n1,n2); LL c = a2-a1; if(c%d) return false; c = (c%n2+n2)%n2; c /= d; n1 /= d; n2 /= d; c *= inv(n1,n2); c %= n2; c *= n1*d; c += a1; n3 = n1*n2*d; a3 = (c%n3+n3)%n3; return true; } //求模线性方程组x=ai(mod ni),ni可以不互质 LL China_Reminder2(LL len, LL* a, LL* n)//len为模方程的式子总数,a[i]、n[i]分别表示第i个式子的余数、除数 { LL a1=a[0],n1=n[0]; LL a2,n2; for(int i = 1; i < len; i++) { LL aa,nn; a2 = a[i],n2=n[i]; if(!merge(a1,n1,a2,n2,aa,nn)) return -1;//无解输出-1 a1 = aa; n1 = nn; } Mod = n1; return (a1%n1+n1)%n1; } LL a[1000],b[1000]; int main() { int i; int k; while(scanf("%d",&k)!=EOF) { for(i = 0; i < k; i++) scanf("%I64d %I64d",&a[i],&b[i]); printf("%I64d\n",China_Reminder2(k,b,a)); } return 0; }
相关文章推荐
- 四则运算表达式解析
- python数据类型——字典
- 滴滴快车奖励政策,高峰奖励,翻倍奖励,按成交率,指派单数分级(8月17日~8月23日.)
- 用栈判断字符串匹配问题
- python练习
- 前端开发:用户体验不佳的八大细节
- Maven更改默认Jdk版本
- Django book 笔记---Form表单
- python2.7.10安装配置
- gif表情
- IOS 学习记录 表格单元格放入缓存池
- 获取图片每(某)个像素点的RBGA值
- 士兵调用枪的问题
- python 流程控制
- PAT 1091. Acute Stroke (30)
- Android FragmentManager BackStackRecord.run throwing NullPointerException
- 第5章 跳跃表
- application/x-www-form-urlencoded等字符编码的解释说明(http)
- 微软小冰智能聊天是如何实现的?
- 即时通讯 聊天界面 listview 中 所有的语音的列表