线性同余系列

线形同余方程系列

求解形如 :  ax ≡ b (mod n)

方程可以变形为 : ax – ny = b; 对于这个方程的求解可以使用扩展欧几里得定理做,有解的首要条件便是 b 能够整除 gcd(a ,n); 证明如下: 如果b 不能够整除 (a ,n),那么方程两边同除以(a ,n),有 a’x – n’y = b/(a ,n) ; 可以看出,方程左边肯定是整数,右边却为小数,所以b肯定能整除 (a ,n);

对于方程: ax – ny = gcd(a ,n);通过扩展欧几里得可以求出方程的某个解: 假设求得x0,那么方程其余解可以表示为 : x0 + k* n/(a ,n); k∈Z(对于这个通解,我参考很多网上的资料,可是说得都不是很清楚,智商不高的我表示我研究两天才有所领悟) ; 首先,由于y=ax/n; (这里的除法是计算机语言中的除法) 也就是说随着 x 的变化,y是可以相应变化。。 那么,x0满足条件 ,x1=x0+n也满足条件,对应y1=y0+a; 但我们可以缩小这个间距,那么是不是y1=y0+1;满足条件呢?此时的x1=x0+n/a; 但由于求的是整数解,我们无法保证n/a 是一个整数。那么也就是说我们要找的就是t ∈ [1,n],使得n/t是个整数且t最大,当然同时还要满足a*n/t % n==0;

那么就有a/t *n % n ==0; 也就是 a / t 也得是一个整数,那么能够被a、n整除的最大t便是 gcd(a ,n);所以 通解为 xk= x0 + k*n/(a ,n); k∈Z; (为啥总觉得自己把一个很简单的问题想得太复杂呢。。。因为通过这个式子:  ,可以很容易看出 通解的间距为: n’; 66666... )

 现在来看线性同余方程组:

解决形如:  x ≡ b1 (mod a1);  ①

    x ≡ b2 (mod a2);  ②

x ≡ bi (mod ai);

解决方法是两两一对求解,然后再通过得到的解构造一个新的方程,然后递推求解。

首先: 由 ①、② 得 a1 * k1 – a2 * k2 = b2 - b1; ③

那么方程组有解的首要条件便是 gcd(a1,a2) | (b2-b1);如果不满足这个条件,方程无解。

式子 a1 * k1 – a2 * k2 = gcd(a1,a2);通过扩展欧几里得定理可以求出某个解k1, 那么式子 ③ 中的k1=k1*(b2-b1)/(a1,a2);

由于要让k1 尽量小,且为正整数 ; 令 t= a2/(a1,a2); 那么有k1=(k1 % t + t ) % t; (t 的由来参看上部分)

现在可以明了方程组的解为 x = a1 * k1 + b1; ④

那么可以构造出第三个式子 : b1 = x; a1= lcm[a1,a2];

关于构造第三个式子的理解: 如果只有两个方程式子,那么现在得出的解x便是满足条件的最小解x,但如果还有第三或者更多的线性同余方程,那么如果最后的解x’大于x,那么他必然满足 x’% lcm[a1,a2] == x; 即 x’就是 ④ 的通解 。

如果说上面的理解还有需要想象的地方(0.0 我反正找不到...),那么下面我给出比较严谨的公式推导过程:

x ≡ b1 (mod a1);  ①

 x ≡ b2 (mod a2);  ②

由 ① 得 x = a1*k1+b1; ③

将 ③ 代入 ② :有 a1*k1+b1 ≡ b2 (mod a2) ;

 --> a1*k1 ≡ b2-b1 (mod a2); ④

 令 d= gcd(a1,a2);   B= b2-b1;

 由 ④ 有: a1*k1 = k2*a2+B;

 --> a1*k1/d = k2*a2/d + B/d ;

 令B’= B/d;

 有 a1*k1/d = k2*a2/d + B’; ⑤

 由 ⑤ 得: a1*k1/d ≡ B’(mod a2/d);

 --> k1 ≡ K (mod a2/d);

 --> k1 = k’*a2/d + K; ⑥ 

 将 ⑥ 代入 ③ :

 x = (k’*a2/d + K)*a1+b1;

 --> x = k’*a1*a2/d +K*a1 +b1;

 --> x ≡ K*a1 +b1 (mod a1*a2/d); ⑦

 由 ⑦ 也验证了构造出来的新方程的a’= a1 * a2 / d ; b’= K * a1 + b1 ;

上面讨论的是方程组x前面没有系数的情况,但如果前面存在系数w1,做法也几乎一样,就是先两边同除以gcd(wi,ai);得到式子:wi’* x ≡ bi’(mod ai’),然后化为x ≡ bi’/ wi’(mod ai’);上述过程中如果出现除不尽的情况就表示无解..,

以上的解法是通用于这类型题的,如果题目中多一个限制条件:强调a1、a2、…、ak是互质的,那么可以用中国剩余定理来解,解法如下:

从刚才通用的解法中,我们也可以看出最后的解范围为0<=x<=lcm[a1,a2,…,ak],如果a1、a2等是互质的话,设他们的最小公倍数为M,M=a1*a2*…*ak;记Mi=M/ai;那么必然存在整数解p,q使得Mi*pi+ai*qi=1;(因为gcd(Mi,ai)==1,这个就不用我解释吧),记ei=Mi*pi;那么有:

ei ≡ 0 (mod aj) ;  j!=i;  这个比较好理解吧,Mj中包括着ai;

ei ≡ 1 (mod aj) ;  j==i; Mj中不包括ai;

所以可以很容易得出,线性同余方程组的通解为 x = e1*b1+e2*b2+ ...+ek*bk ; 这个就是单纯地从定义得到, 比如 :e1 % a1 = 1 ; 那么 e1 * b1 % a1 =b1; 而其他项取余 a1 都等于0,所以得出的这个式子肯定满足上面那k个线性同余方程,当然,如果想要最小正整数解,可以通过加减M来得到。这个适用于a1、a2、…、ak互质的情况。

……以上就是解决线性同余方程组的方法了。

给一道模板题: http://acm.fzu.edu.cn/problem.php?pid=1402

 

 1 #include<stdio.h>
 2 typedef long long LL;
 3 void exGcd(LL a,LL b,LL &d,LL &x,LL &y)
 4 {
 5   if(b==0)
 6   {
 7     d=a;
 8     x=1;
 9     y=0;
10   }
11   else
12   {
13     exGcd(b,a%b,d,x,y);
14     int t=x;
15     x=y;
16     y=t-a/b*y;
17   }
18 }
19 int main()
20 {
21   LL n,a1,a2,b1,b2;
22   LL x,y,d,ans;
23   while(scanf("%I64d",&n)!=EOF)
24   {
25     ans=1;
26     scanf("%I64d%I64d",&a1,&b1);
27     for(LL i=1;i<n;i++)
28     {
29       scanf("%I64d%I64d",&a2,&b2);
30       exGcd(a1,a2,d,x,y);
31       if((b2-b1)%d!=0)
32       {
33         ans=0;
34       }
35       LL t=a2/d;
36       x=(x*(b2-b1)/d%t+t)%t;
37       b1=a1*x+b1;
38       a1=a1*a2/d;
39     }
40     if(ans!=0)
41       printf("%I64d\n",b1);
42   }
43   return 0;
44 }
时间: 2024-12-26 09:24:44

线性同余系列的相关文章

POJ 3087 Shuffle&#39;m Up 线性同余,暴力 难度:2

http://poj.org/problem?id=3087 设:s1={A1,A2,A3,...Ac} s2={Ac+1,Ac+2,Ac+3,....A2c} 则 合在一起成为 Ac+1,A1,Ac+2,A2......A2c,Ac 经过一次转换之后变成 s1={Ac+1,A1,Ac+2.....} s2={...A2c,Ac} 对应之前,每个数的序号发生的变化是 +1,+2,+3....-c,-c+1,..... 把整个数链想成环,也相当于是: +1,+2,+3....+c,+c+1,...

一、解密随机数生成器(2)——从java源码看线性同余算法(转)

上篇博客中,我们了解了基于物理现象的真随机数生成器,然而,真随机数产生速度较慢,为了实际计算需要,计算机中的随机数都是由程序算法,也就是某些公式函数生成的,只不过对于同一随机种子与函数,得到的随机数列是一定的,因此得到的随机数可预测且有周期,不能算是真正的随机数,因此称为伪随机数(Pseudo Random Number). 不过,别看到伪字就瞧不起,这里面也是有学问的,看似几个简简单单的公式可能是前辈们努力了几代的成果,相关的研究可以写好几本书了!顺便提一下,亚裔唯一图灵奖得主姚期智,研究的就

解密随机数生成器(二)——从java源码看线性同余算法

Random Java中的Random类生成的是伪随机数,使用的是48-bit的种子,然后调用一个linear congruential formula线性同余方程(Donald Knuth的编程艺术的3.2.1节) 如果两个Random实例使用相同的种子,并且调用同样的函数,那么生成的sequence是相同的 也可以调用Math.random()生成随机数 Random实例是线程安全的,但是并发使用Random实例会影响效率,可以考虑使用ThreadLocalRandom变量. Random实

解线性同余方程组

想必学完exgcd的各位dalao们都已经明白如何求解同余方程了 今天本蒟蒻只是想讲讲线性同余方程组的解法供各位大佬批评指错 我们现在有一些线性同余方程 X=b1 (mod a1) X=b2 (mod a2) ... X=bn (mod an) 对于前面第一个方程,我们可以用exgcd求出一个X满足一式 不妨设X=a1*y1+b1 若存在X满足二式,则a1*y1+b1=b2 (mod a2) 所以y1=(b2-b1)/a1 (mod a2) 该式有解当且仅当(b2-b1)|gcd(a1,a2)

线性同余方程组

线性同余方程组就是由多个线性同余方程联立得到的.用数学符号表示就是求解ai*x≡bi(mod m)(1≤i≤n)这样的方程. 可知解的全集一定可以写成x≡b(mod m)的形式,因此我们只要对所有线性同余方程依次求解即可. 因为x≡b1(mod m1),所以将x写成x=b1+m1*t并代入第二个式子,可得 a(b1+m1*t)≡b2(mod m2) 整理得 a*m1*t≡b2-a*b1(mod m2) 然后求解这个一次同余方程即可.当gcd(m2,a*m1)无法整除b2-a*b1时原方程组无解.

HDU 3579 线性同余方程组

#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int MaxM=11; int a[MaxM],b[MaxM]; void exgcd(int a,int b,int &d,int &x,int &y){ if(b==0){ x=1; y=0; d=a; } else{ e

hdu1573:数论,线性同余方程组

题目大意: 给定一个N ,m 找到小于N的  对于i=1....m,满足  x mod ai=bi  的 x 的数量. 分析 先求出 同余方程组 的最小解x0,然后 每增加lcm(a1...,am)都会存在一个解,注意必须小于N 不能等于 代码: #include <iostream> #include <stdio.h> #include<string.h> #include<algorithm> #include<string> #inclu

poj 1061(线性同余)

青蛙的约会 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 104278   Accepted: 20356 Description 两 只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面.它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止.可是它 们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置.不过青蛙们都是很乐观的,它们觉得只要一直朝着某个方向跳下去

POJ 1426 Find the Multiple 思路,线性同余,搜索 难度:2

http://poj.org/problem?id=1426 测试了一番,从1-200的所有值都有long long下的解,所以可以直接用long long 存储 从1出发,每次向10*s和10*s+1转移,只存储余数即可, 对于余数i,肯定只有第一个余数为i的最有用,只记录这个值即可 #include <cstdio> #include <cstring> #include <queue> using namespace std; const int maxn=222