【转】初等数论 ——原根、指标及其应用
轉(zhuǎn)自:http://blog.163.com/gc_chdch@126/blog/static/172279052201641935828402/
?
?
學習總結(jié):初等數(shù)論(3)——原根、指標及其應用??
2016-05-19 15:58:28|??分類:?信息學——學習總?|??標簽:初等數(shù)論??數(shù)學??|舉報|字號?訂閱
學習總結(jié):初等數(shù)論(3)——原根、指標及其應用
?
最近知道了一本書叫《數(shù)論概論(第3版)》(A Friendly Introduction to Number Theory),簡單翻了翻,感覺這本書寫的非常好。想起以前剛接觸數(shù)論時,沒有看這本書來入門,真是十分遺憾。這本書面向非數(shù)學專業(yè)讀者,語言生動幽默而不失嚴謹性,注重對知識的感性認識(用了大量的例子),和對數(shù)學思想和方法的滲透(比如:大膽猜想規(guī)律,證明時用“計數(shù)”法等)。這里強烈推薦這本書!
?
下面總結(jié)一下這幾天學習的內(nèi)容。
?
一、整數(shù)的階
a與n是互質(zhì)的兩個數(shù)。可以發(fā)現(xiàn),總存在某個數(shù)x,滿足?ax?≡ 1(mod?n)。
使ax?≡ 1(mod?n)滿足的最小的正整數(shù)x叫做a模n的階(或次數(shù)),記做ena(有的地方記做ordna)。
怎么理解呢?你要不斷計算a,a2,a3,…,(注意要模n)我們知道,根據(jù)鴿巢原理,一定會有循環(huán)。而a和n互質(zhì)時,總會在某個時刻出現(xiàn)了1,下一個時刻又是a,……于是就有了循環(huán)。這個出現(xiàn)1的最小的指數(shù),叫做a的階。
比如:我們要找3模7的階,計算31,32,…,36模7的值依次為:
3,2,6,4,5,1,
所以我們得到3模7的階為6。
?
a與n互質(zhì)時,根據(jù)歐拉定理有a?(n)≡1(mod?n)。這么說來,剛才我們不斷計算a的冪的循環(huán)節(jié)的長度(即a的階)“擴增”若干次后應該為?(n)。所以,
ena?|??(n)。
同樣的道理,為了使方程?ax≡1(mod?n)有解,應該把循環(huán)節(jié)長度“擴增”若干次后得到x,所以
ena?|?x
?
二、原根
設a與n是互質(zhì)的整數(shù),當a模n的階為?(n)時,把a叫做n的原根。
怎么理解呢?我們計算a的冪的序列,第一次得到1的時候,得到了完整的一個循環(huán)節(jié)。我們上面已經(jīng)說了,?(n)一定是(a模n的階)的倍數(shù)。如果這個循環(huán)節(jié)的長度恰好就是?(n)(循環(huán)節(jié)的長度已經(jīng)達到最大了),那么a就是n的原根。
?
(1)原根的存在性
一個數(shù)可能有很多個原根,也可能沒有原根。可以證明:
正整數(shù)n存在原根,當且僅當
n?= 2, 4,?pt或2pt(其中p是奇素數(shù),t是正整數(shù))。
舉例:5的原根有2和3;7的原根有3和5。
?
(2)原根的一個性質(zhì)
原根為什么這么重要?
設g是n的一個原根,那么:g,g2,g3,…,g?(n)(即g0≡1(mod?n))一定兩兩不同。(如果有相同,比如說存在0≤i<j<?(n)滿足gi≡gj(mod?n),那么就會有gj-i≡1(mod?n),而j?–?i<?(n),這時?(n)就不是g的階了)
看看方程ax≡1(mod?n),如果x是存在的,那么a一定是與n互質(zhì)的數(shù)(如果a和n有某個大于1的公因子,無論a怎么取冪再模n,這個公因子都“消不掉”,不會有ax?mod?n?= 1)。所以“合法”的a有?(n)個。而我們找到一個原根g后,g的冪(g,g2,g3,…,g?(n))一定就是這些合法的a(即與n互質(zhì)的?(n)個數(shù)。因為g與n互質(zhì),g的冪也與n互質(zhì),而這些冪又兩兩不同,一定能把“與n互質(zhì)的數(shù)”取盡)。
一句話總結(jié)上面的內(nèi)容:對于n的一個原根g,滿足
{ 1,g,g2,g3,…,g?(n) – 1?} = {?x?|?x與n互質(zhì),1≤x<n?}
特別地,對于奇質(zhì)數(shù)p的一個原根g,滿足
{ 1,g,g2,g3,…,gp?– 2?} = { 1, 2, 3, …,?p?– 1 }
(3)原根的個數(shù)
一個數(shù)n,如果存在原根,就一定?(?(n))個。怎么證明呢?為此我們先討論下面這個問題:
?
已知a模n的階ena,怎么求au的模n的階?
設au模n的階為t,那么t應該是最小的正整數(shù),滿足(au)t≡aut≡1 (mod?n)。
由之前的討論,可以知道:u×t應該是ena的倍數(shù),并且t最小。
由數(shù)論的基本知識可以得出,enau?=?t?=?ena?/ gcd(u,?ena)。
?
如果我們找出一個原根g,怎么得出其他的原根?
首先,其他的原根一定是g的若干次冪。
哪些“g的若干次冪”可以成為原根?
用原根的定義!
對于某個“g的若干次冪”,比如gi?(0≤i<?(n)),由上面的結(jié)論得出,它模n的階為
?(n) / gcd(i,??(n))
欲使它的階也為?(n),即
?(n) / gcd(i,??(n)) =??(n)
需要使gcd(i,??(n)) = 1,也就是i和?(n)互質(zhì)。
有多少個i滿足它和和?(n)互質(zhì)?換句話說,在0 ~??(n)–1的數(shù)中,有多少個與?(n)互質(zhì)?答案應該是?(?(n))。所以,一個數(shù)如果有原根,那么它有?(?(n))個原根。
?
下面舉個例子:
7的原根有?(?(7)) =??(6) = 2個,最小的一個是3。
在32,33,…,36中,哪個指數(shù)與6互質(zhì)?只有5,所以另一個原根是35≡5(mod 7)。
?
怎么找原根?
通常最小的原根都比較小,所以暴力從1開始枚舉就可以了。判斷一個數(shù)a是不是n的原根,需要判斷?(n)是否是a的階,直接的判斷方法是枚舉?(n)的每一個因子d(除去它本身),判斷是否ad≡1(mod?n)。但這樣做了很多重復的判斷。
比如我們要判斷a模n=37的階是否為36,那么只需找出36的兩個質(zhì)因子2和3,只需判斷36/2和36/3作為a的冪的指數(shù)時,(a的冪) mod?n是否為1。如果a的階為36/4,36/9,36/6,36/12,…,其實情況已經(jīng)包含在上面的判斷中了。(比如,如果a36/9≡a4≡1(mod?n),那么一定也會滿足a36/2≡3618≡1(modn))。
?
三、指標(離散對數(shù))
求原根有什么作用?為了計算指標!
對于n的一個原根g,滿足
{ 1,g,g2,g3,…,g?(n) – 1?} = {?x?|?x與n互質(zhì),1≤x<n?}
再具體一些,可以定義一種“求冪”的運算,這種運算揭示了兩個集合的一一對應關系:
i?→?gi?(1≤i≤?(n))
為什么是一一對應關系?因為gi一定兩兩不同。這一點已經(jīng)討論過了。
?
那么,是否有一種“求冪”運算的逆運算?有!
求出n的一個原根g,知道了某個與n互質(zhì)的數(shù)a,n是g的多少次方?
我們用I(a)來表示這個“次方”數(shù),叫做以g為底a模n的指標。(有的地方記做indga)
也就是,依照定義,應該有gI(a)≡a(mod?n)(a與n互質(zhì))。
顯然,指標的范圍是0≤I(a)<?(n),當指標超過?(n)時,出現(xiàn)了循環(huán),可以把指標mod??(n)進行簡化。
有點像我們以前學過的對數(shù)?(不嚴謹?shù)恼f,有點像logga?)也許這就是為什么指標也叫離散對數(shù)了。
?
當n為質(zhì)數(shù)時,原根g一定存在,而且?(n) =?n?– 1,這樣,每個在1~n–1范圍內(nèi)的數(shù)都有指標!
?
我們可以根據(jù)冪的運算法則,對應得出指標的運算法則:
(1)?I(ab) =?I(a) +?I(b) (mod??(n)) ?(類比:logaNM?= logaN?+ logbM)
(2)?I(ak) =?k×I(a) ? (類比:logaNM?=?M×logaN)
指標把乘法變加法,把冪變乘法,這一點與對數(shù)的運算法則多么相似!
?
如果有一個指標表,我們可以十分簡便地進行運算。舉例:
n?= 37,它的一個原根是a?= 2。
要計算23×19 mod 17的值,可以計算
I(23×19) ≡?I(23) +?I(19) ≡ 15 + 35 ≡ 50 ≡ 14 (mod 36)
然后,查表可以得出,指標為14的數(shù)是30,就是要求的答案了。
很麻煩?
再看一個例子:
I(2914) ≡ 14 ×?I(29) ≡ 294 ≡ 6 (mod 36)
由表得:I(27) = 6,所以2914?≡ 27 (mod 37) ?
你也許會說:有快速冪!在前兩個例子中,似乎指標的優(yōu)勢沒有體現(xiàn)出來。不過,在解方程的時候,指標就很有用了。
解同余式:
擴展歐幾里得?好像也能解。不過,像下面這樣的同余式呢?
只能用指標來解。兩邊同時求離散對數(shù):
可以解出:
事實上,最后一個例子是指標最重要的運用之一。等會兒我們會詳細討論。
?
但是,之前的計算都是在指標表已經(jīng)給了的情況下進行的。沒有指標表怎么辦呢?如何求某個數(shù)指標(離散對數(shù))?
更準確地說,給出g,?a,?p,如何求gk?≡?a(mod?p)的最小的k?為了簡化問題,這里規(guī)定p為質(zhì)數(shù)。
這里使用一種叫做大步小步(gaint-step?baby-step)的算法。算法的核心思想是分塊。取m?= [ sqrt(p?– 1) ] + 1,然后把k表示成xm?+?y?(0 ≤?y?<?m)的形式。這樣,x和y的范圍都是0~m(y不含m)。于是gk?≡ (gm)x?×?gy,可以求出所有的gy(m個取值);然后枚舉x,計算出(gm)x,查找:是否存在某個gy滿足(gm)x?×?gy?≡?a(mod?p)?也就是說:
是否存在某個gy,滿足gy?≡?a?× (gmx)?–1?(mod?p)?
用費馬小定理和快速冪求出逆元(gmx)?–1,然后求出a?× (gmx)?–1。檢查是否有“匹配”的gy。如果我們先把gy放在一個哈希表(或者C++的map)中,那么這一步的查詢就是O(1)(或O(log2m)=O(log2p))的。算法的核心步驟仍然是枚舉,但分塊使時間復雜度變成O(sqrt(P) × log2P)(注意算上求逆元的時間)。
?
四、N次剩余
這里要解決一個這樣的問題:
給出N,?a,?p,求滿足xN?≡?a?(mod?p)(p為質(zhì)數(shù))的所有解x。
可以形象地理解成求a在模p意義下的N次方根。
?
剛才我們已經(jīng)借助例子,初步了解了做法:
xN?≡?a?(mod?p),找出p的一個原根g,用“大步小步”算法求出以g為底a模p的指標I(a)。
同余式變成:
N?×?I(x) ≡?a?(mod?p?– 1)
?
由一次同余方程的知識可以知道,有解的條件是
gcd(N,?p?– 1) |?a
而且,解有gcd(N,?p?– 1)個。
?
解出所有的可能的I(x),那么x?=?gI(x)。這些x中重復的要去掉。
?
代碼:
| #include ?<cstdio> #include ?<cstring> #include ?<algorithm> #include ?<cmath> #include ?<vector> #include ?<map> using ?namespace std; ? typedef ?long long LL; ? int ?gcd(int a, int b) { ? return b == 0 ? a : gcd(b, a % b); } ? void ?_gcd(int a, int b, LL &x, LL &y) { ? if (b == 0) ? { ? ? ? x = 1; y = 0; ? ? ? return ; ? } ? _gcd(b, a%b, y, x); ? y -= (a/b) * x; } ? int ?extend_gcd(int a, int b, int c, LL &x, LL &y, int &dx, int ?&dy) { ? int g = gcd(a, b); ? if (c % g) return 0; ? _gcd(a, b, x, y); ? x *= (c/g); ? y *= (c/g); ? dx = b / g; ? dy = a / g; ? return g; } ? // Ax ?= B (mod N) //?設Ax = ?-yN + B //?則Ax + ?Ny = B bool ?line_mod_equ(int A, int B, int N, int &x, int &k) { ? LL x0, y0; ? int dx, dy; ? if (!extend_gcd(A, N, B, x0, y0, dx, dy)) ?return false; ? x0 %= dx; ? if (x0 < 0) x0 += dx; ? x = (int)x0; ? k = dx; ? return true; } ? LL ?pow_mod(LL a, LL b, LL p) { ? if (b == 0) return 1; ? LL tmp = pow_mod(a, (b>>1), p); ? if (b & 1) return tmp * tmp % p * a % ?p; ? ? ? else return tmp * tmp % p; } ? //分解質(zhì)因數(shù) void ?factor(int x, vector<int> &divs) { ? divs.clear(); ? for (int i = 2; i * i <= x; ++ i) ? ? ? if (x % i == 0) ? ? ? { ? ? ? ? ?divs.push_back(i); ? ? ? ? ?while (x % i == 0) x /= i; ? ? ? } ? if (x > 1) divs.push_back(x); } ? bool ?g_test(int g, vector<int> &divs, int P) { ? for (int i = 0; i < (int) divs.size(); ?++ i) ? ? ? if (pow_mod(g, (P-1) / divs[i], P) == ?1) return false; ? return true; } ? //找原根,p為質(zhì)數(shù),保證有原根 int ?primitive_root(int P) { ? static vector<int> divs; ? factor(P-1, divs); ? int g = 1; ? while (!g_test(g, divs, P)) ++ g; ? return g; } ? //?求解在模P意義下,以a為底N的離散對數(shù)b (P為質(zhì)數(shù)) //?即?a ^ b ?= N (mod P) //?大步小步算法(分塊) //?取s = ?sqrt(P),?設b = x * s + y //?則?a ^ ?(x*s + y) = (a^s)^x * a^y = N (mod P) //?求出y = ?0~s-1時,?a^y的取值;然后枚舉s,算出(a^s)^x,查找是否有匹配的y int ?discrete_log(int a, int N, int P) { ? map<int, int> rec; ? int s = (int)sqrt(P + 0.5); ? while (s * s <= P) ++ s; ? LL cur = 1; ? for (int y = 0; y < s; ++ y) ? { ? ? ? rec[ cur ] = y; ? ? ? cur = cur * a % P; ? } ? LL a_s = cur; // a^s ? cur = 1; ? for (int x = 0; x < s; ++ x) ? { ? ? ? LL a_y = pow_mod(cur, P-2, P) * LL(N) % ?P; ? ? ? map<int,int> :: iterator it = ?rec.find( a_y ); ? ? ? if (it != rec.end()) return x * s + it ?-> second; ? ? ? cur = cur * a_s % P; ? } ? return -1; } ? // x ^ ?K = A (mod P) (where P is a prime) //?找p的一個原根g,求出指標 // K ?I(x) = I(A) (mod P-1) //?有解的條件?gcd( ?I(x), P-1 ) | I(A) void ?discrete_root(int K, int A, int P, vector<int> &x) { ? x.clear(); ? if (A == 0) { x.push_back(0); return ; } ? int g = primitive_root(P); ? int IA = discrete_log(g, A, P); ? int Ix, delta; ? if (!line_mod_equ(K, IA, P-1, Ix, delta)) ?return ; ? while (Ix < P) ? { ? ? ? x.push_back( pow_mod(g, Ix, P) ); ? ? ? Ix += delta; ? } ? sort(x.begin(), x.end()); ? x.erase(unique(x.begin(), x.end()), ?x.end()); } ? int ?main() { ? int P, K, A; ? scanf("%d%d%d", &P, &K, ?&A); ? static vector<int> x; ? discrete_root(K, A, P, x); ? printf("%u\n", x.size()); ? for (int i = 0; i < (int) x.size(); ++ ?i) printf("%d\n", x[i]); ? return 0; } ? |
2016-09-06?20:59:38
轉(zhuǎn)載于:https://www.cnblogs.com/Konjakmoyu/p/5847136.html
總結(jié)
以上是生活随笔為你收集整理的【转】初等数论 ——原根、指标及其应用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 新知识点
- 下一篇: 元气骑士界面皮肤如何更改?