标签:style blog http color os for art ar
以前觉得用中国剩余定理来求同余方程组很鸡肋,因为可以用拓展欧几里得算法来构造出一种更加强大(可以处理取模的数(默认为mi)不互质的情况)的算法。
今天查了点资料,发现我太天真了。
首先讲讲中国剩余定理:
即 : x ≡ a[i] (mod m[i]) 1<= i <= r (m[i] 两两互质)
求这个同余方程组可以快速算:
x = ∑M/m[i] * Inv(M/m[i], m[i]) * a[i] (mod M) 其中M = m[1]*m[2]*m[3]...m[r] , Inv(x, y) 表示x在模y下的逆元
讲讲我对这个方程的理解:
1) 因为m[i]是两两互质的,所以gcd(M/m[i], m[i]) == 1,也就是说逆元一定存在,所以这个方程一定有解(对m[i]两两不一定互质的情况要小心解不存在的情况,即逆元不存在)。
2) 然后,为什么这个解就一定是这个同余方程组的解呢?是这样的,首先M/m[i] 对于除了m[i]外其他的m[k]的话都是能够被整除的,而M/m[i] * Inv(M/m[i], m[i])*a[i]这一部分对m[i]取模肯定是a[i],因为M/m[i] * Inv(M/m[i], m[i]) ≡ 1(mod m[i]),所以∑M/m[i] * Inv(M/m[i], m[i]) * a[i]肯定是满足要求的一个解。
3) 代码实现
1 typedef long long lld; 2 lld exgcd(lld a, lld b, lld &x, lld &y) { 3 if (!b) { 4 x = 1; y = 0; 5 return a; 6 } 7 lld ret = exgcd(b, a % b, y, x); 8 y -= (a/b) * x; 9 return ret; 10 } 11 lld Inv(lld a, lld MOD) { 12 lld x, y; 13 lld d = exgcd(a, MOD, x, y); 14 return d == 1 ? (x%MOD+MOD)%MOD : printf("no~\n"); 15 } 16 lld China(int a[], int n, int m[]) { 17 lld M = 1, ret = 0; 18 for (int i = 1; i <= n; i++) M *= m[i]; 19 for (int i = 1; i <= n; i++) { 20 lld w = M/m[i]; 21 ret = (ret + w * Inv(w, m[i])% M * a[i] % M) % M; 22 } 23 return ret; 24 }
独立剩余:
其实上面的内容就是我觉得“鸡肋”的地方,恩,有关独立剩余才是真正的体现CRT用处的地方,由于我自己现在还只是初步的了解,所以有可能出错,敬请原谅。
同余式: Res(x) = (x mod m[1], ..., x mod m[r]), 且m[i]两两互质 对于一个大于1的数x,我们都可以表示 x = ∏p[i] ^ {k[i]} k[i] >= 1,所以很多地方一个数你可以拆成多个不同的素数的积,这样两两互质这一条件一定成立。
然后同余式有个规则(?)就是我们可以在每一个分量上进行独立的执行加法,减法和乘法。 这是一个很赞的地方,比如对于一个M = 30 , 我们可以对于2、3、5分别进行模运算,最通过"某种方法“还原成对于30的模运算结果,这往往可以获得意想不到的效果(虽然我还没做过类似的题目= =)
哦,所谓的”某种方法“就是中国剩余定理,我们可以类似的向量般的处理(1, 0, 0) = a, (0, 1, 0) = b, (0, 0, 1) = c对于M = 30我们可以把它看做一个三维向量,那么(x, y, z) = (a*x+b*y+c*z) mod 30
现在我们需要的是计算出a、b、c的值,当然如果M比较小的话,你可以暴力去找,复杂度O(M),M较大的时候就可以套中国剩余定理了,不过不用∑,也就是M/m[i] * Inv(M/m[i], m[i]) * a[i], 这么一项就行了,(其实只要算一个拓展欧几里得的就行了,只是样子有点象CRT而已 = =)
好吧,暂时理解就到这了(写这个主要还是加深印象)= =,继续看书... 未完待续....勿喷....
对于中国剩余定理(CRT)的初步理解,布布扣,bubuko.com
标签:style blog http color os for art ar
原文地址:http://www.cnblogs.com/danceonly/p/3901595.html