標籤: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 }View Code
獨立剩餘:
其實上面的內容就是我覺得“雞肋”的地方,恩,有關獨立剩餘才是真正的體現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而已 = =)
好吧,暫時理解就到這了(寫這個主要還是加深印象)= =,繼續看書... 未完待續....勿噴....