日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

数论入门

發(fā)布時(shí)間:2023/12/31 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数论入门 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

數(shù)論入門

雖然大一學(xué)c語言的時(shí)候就學(xué)了輾轉(zhuǎn)相除法也(歐幾里得算法),但是當(dāng)時(shí)沒學(xué)透,沒有搞清楚為啥子這樣輾轉(zhuǎn)相處就能得到最大公約數(shù),這來一段書上的話

確實(shí)這么一段話就搞清楚為啥要輾轉(zhuǎn)相除了,然后就是擴(kuò)展歐幾里得算法,而擴(kuò)展歐幾里得算法就是用來解決線性同余方程的ax ≡ c (mod b),夜深人靜寫算法(初等數(shù)論) , 這篇文章講得很細(xì), 文中的推導(dǎo)就是d = gcd(a, b) = gcd(b, a%b) = bx' + (a%b)y' = bx' + [a-b*(a/b)]y' = ay' + b[x' - (a/b)y']

模板代碼:

int ex_gcd(int a, int b, int &x, int &y){if(b == 0){x = 1; y = 0;return a;}else{int answer = ex_gcd(b, a%b, x, y);int temp = x;x = y;y = temp - a/b * y;return answer;} }

我也想了一哈非遞歸的代碼,但是確實(shí)目前水平不夠,想不出來,因?yàn)檫@個(gè)不像輾轉(zhuǎn)相除法可以遞推,這個(gè)必須先遞歸到底,然后再回來的時(shí)候才能根據(jù)求得的x,y遞推

poj1061 poj2115
poj1061這是擴(kuò)展歐幾里得算法的入門題,poj2115也是類似, 也可以歸為線性同余方程,就是兩只青蛙一只切追另外一只,當(dāng)讓肯定要速度快的去追速度慢的。我第一反應(yīng)就是用小學(xué)學(xué)的追擊問題切解決,但是有問題,因?yàn)樗麄冏叩穆肥且粋€(gè)環(huán)也就是說雖然使用路程差 / 速度差 = 所需次數(shù) 但是,這里的速度有可能是大于路程差的而且青蛙是一次一次的跳也就是整數(shù),不能結(jié)果來小數(shù),也就是速度快的那只青蛙有可能直接一跳直接就跳到了速度慢的那只青蛙的前頭,然后他們就有可能繞地球及幾圈以后才會相遇,這么以來就不能直接除了,但是也不能就用暴力慢慢搞跳幾次才相遇三,所以就用到了傳說中線性同余方程速度差 * x ≡ 路程差(mod 總路程),然后就用擴(kuò)展歐幾里得算法套就行了,但是求出來的是這是其中一個(gè)解,而題目中要求最小非負(fù)解,這就需要對同余方程解一個(gè)深刻理解才能很自然的用通解得到

博客推薦
青蛙約會詳解
青蛙題解
這是我從文中截圖,這里講得很到位,一看就懂,一哈就領(lǐng)會了啥子通解,在那個(gè)范圍由唯一解這些東西, 然后這道題也就出來了

還有一個(gè)小問題就是c++的負(fù)數(shù)取模

int a = -3;cout << a % 2 << endl;

結(jié)果是 -1

poj2142
這道題跟上面的也差不多,也要先用擴(kuò)展歐幾里得算法處理,然后對于解體重要求在所有的解中,取砝碼數(shù)量最小的組合, 如果砝碼組合相同,就取用的砝碼總重量最小的組合,這道題的難點(diǎn)也就在這,求兩種砝碼數(shù)量總和最小的那組。
我是通過畫圖來解決,因?yàn)樯厦嫠v的,通解可以表示為

x = (x0 + kb/gcd)y = (y0 - ka/gcd)

當(dāng)然后這里的x ,y有可能一正一負(fù), 也有可能都為正,所以要求 x + y 的最小值 也就是要求 |x| + |y|, 這里就用到了高中學(xué)的東西,圖中為這兩個(gè)絕對值的圖像,因?yàn)榧恿私^對值,x下面的部分都翻了上來,然后x和y和x軸一定各自相較于一點(diǎn),然后這兩個(gè)v字型隨便一定就行了,不管怎么移動,他們必有交點(diǎn),也就是圖中的a點(diǎn),從這的點(diǎn)往右走,|x| + |y|的值會增加因?yàn)?#xff0c;增加了b但是只減少了c,其他區(qū)域都是都是同理,所以那個(gè)最小值的點(diǎn)就是看哪個(gè)函數(shù)斜率大,然后就找斜率大的那個(gè)函數(shù)與x軸的交點(diǎn),然后這個(gè)交點(diǎn)左右最相臨的整數(shù)點(diǎn),判斷這兩個(gè)點(diǎn)是某相等,然后找最小的那個(gè)點(diǎn),然后就簡單了

#include<iostream> #include<cstdio> using namespace std; #define ll long long ll a, b, d, x, y;ll ex_gcd(ll a, ll b, ll &x, ll &y){if(b == 0){x = 1; y = 0;return a;}else{ll answer = ex_gcd(b, a%b, x, y);ll temp = x;x = y;y = temp - a/b * y;return answer;} }ll absabs(ll input){if(input < 0) return -1 * input;return input; }ll funx(ll input){return absabs(input*b+x);} ll funy(ll input){return absabs(y-input*a);} ll fun(ll input){return funx(input) + funy(input); } ll fun2(ll input){return a*funx(input) + b*funy(input); }ll parse(double input, ll &output1, ll &output2){ll param1, param2; if(input >= 0){param1 = (ll)(input + 1);param2 = (ll)input; }else{param1 = (ll)input;param2 = (ll)(input - 1);}// cout << fun(param1) << " *** " << fun(param2) << endl;output1 = param1;output2 = param2; }int main(){while(~scanf("%I64d%I64d%I64d", &a, &b, &d)){if(a==b && b==d && d==0) break;ll yu = ex_gcd(a, b, x, y);a /= yu;b /= yu;d /= yu;x *= d;y *= d;double temp;if(a > b){temp = y*1.0 / a;}else{temp = -1*x*1.0 / b;} ll param1, param2, k;parse(temp, param1, param2); if(fun(param1) == fun(param2)){ if(fun2(param1) < fun2(param2))k = param1;elsek = param2; }else{if(fun(param1) < fun(param2)){k = param1;}else{k = param2;}}cout << absabs(x+k*b) << " " << absabs(y-k*a) << endl; }return 0; }

費(fèi)馬小定理

假如a是整數(shù),p是質(zhì)數(shù),則a,p顯然互質(zhì)(即兩者只有一個(gè)公約數(shù)1),
就有:a^(p-1) ≡ 1 (mod p)
這篇文章是證明過程 :費(fèi)馬小定理
通過這篇文章,根據(jù)3*6*9*12*15*18*21*24*27*30*33*36 ≡ 3*6*9*12*2*5*8*11*1*4*7*10 mod 13 (因?yàn)?和13互質(zhì),所以1,2,.. 12 乘上3后還是和13互質(zhì),12個(gè)數(shù)還是和1到12同余 ,只是順序不同了 )。   所以312×12!≡12!mod 13。
其實(shí)費(fèi)馬小定理成立的根本原因就在于構(gòu)成了312×12!≡12!mod 13,然后兩邊同時(shí)除以那個(gè)階乘就得到了費(fèi)馬小定理,我的第一感覺就是公式中的p不一定非要是素?cái)?shù)公式才成立(已被證明有偽素?cái)?shù)存在,所以確實(shí)不一定是素?cái)?shù)才成立),因?yàn)橹阅軌虺?*6*9*12*15*18*21*24*27*30*33*36 ≡ 3*6*9*12*2*5*8*11*1*4*7*10 mod 13 這種同余式,是因?yàn)閍與p互素,而a與p互素的時(shí)候p不一定是素?cái)?shù)比如3和9,然后a乘以1 2 3 。。。。 n-1, 的時(shí)候之所以能一一對應(yīng)就是因?yàn)檫@個(gè)a在乘的時(shí)候因?yàn)榕cp互素,就會錯(cuò)開,草稿紙上寫一哈就有感覺了。。所以像這種312×12!≡12!mod 13式子很容易得到,比如256 x 8!≡ 8! (mod 9) 但是并不能得到2^8 ≡ 1 (mod 9),這里的問題就是同余式除法,這是從百度上截的圖

但是偽素?cái)?shù)又該怎么解釋喃,如下圖
實(shí)驗(yàn)是檢驗(yàn)整理的唯一標(biāo)準(zhǔn),所以確實(shí)費(fèi)馬小定理前提是必要不充分的,那為什么會有這個(gè)問題?這里就要解決上面的同余式除法的本質(zhì)。這是我從網(wǎng)上看到一個(gè)證明

因?yàn)?m|ac-bc 所以 m/(c,m)|c/(c,m)*(a-b)(m/(c,m),c/(c,m))=1 所以m/(c,m)|a-b 也就是說:a ≡ b (mod m/(c,m))

從這個(gè)證明看出a≡ b (mod m/(c,m)) 其實(shí)本質(zhì)是這個(gè)式子m/(c,m)|c/(c,m)*(a-b),只不過其中而m/(c,m)和c/(c,m)是互素的,所以能判斷(a-b)是被m/(c, m)除盡,而不是c/(c,m)被除盡,但是這并不能說明(a-b)是被m/(c, m)除盡的時(shí)候,c/(c,m)非要和m/(c, m)互素,也就是說他們有可能都被除盡的時(shí)候,而341這個(gè)偽素?cái)?shù)就是這種情況,所以上面同余式除法成立的條件的是必要不充分的所以就導(dǎo)致a^(p-1) x (p-1)! ≡ (p-1)! (mod p) 的時(shí)候要求(p-1) 和 p 互素,也就是為什么費(fèi)馬說p一定要是素?cái)?shù)的原因,因?yàn)槿绻鹥是素?cái)?shù),他們就一定互素。

取模和位運(yùn)算的速度差異

#include<iostream> #include<ctime> using namespace std; #define maxn 300000000 int length = maxn; int shuzu[maxn];int main(){int clock1 = clock();for(int i = 0; i < length; i++) shuzu[i] = 2 * i + 1;for(int i = 0; i < length; i++){if(shuzu[i] % 2 == 1);} cout << "1endl" << endl;cout << "time : " << clock() - clock1 << endl; clock1 = clock();for(int i = 0; i < length; i++){if(shuzu[i] & 1);}cout << "all end " << endl;cout << "time : " << clock() - clock1 << endl;return 0; }

效果:

其實(shí)不管是取模和&運(yùn)算有這種差距,包括除法(/) 和 左移運(yùn)算 (>>) 也有這種差距


判斷素?cái)?shù)的題
poj2262水題,直接試除法
poj3641大整數(shù)判素,需要下面的算法
poj1811需要下面兩個(gè)算法,模板提
poj2429首先要理解最大公約數(shù)和最大公倍數(shù)的關(guān)系,然后就是要枚舉所有組合,我最早感覺枚舉不炫,就自作聰明的想了一些辦法都是錯(cuò)的

拉賓米勒算法(Rabin-Miller)

拉賓米勒算法就是用來判斷素?cái)?shù)的,只不過如果需要判斷的素?cái)?shù)不是很大用這個(gè)算法反而適得其反,比如篩選就相當(dāng)巴適,但是需要判斷的這個(gè)數(shù)是一個(gè)很大的數(shù),比如有18位(long long),如果還用篩選就有點(diǎn)惱火了,因?yàn)椴坏貌徽乙粋€(gè)18位這么長的數(shù)組,而且還要從2一直循環(huán)到1e18,不超時(shí)和不超內(nèi)存都是不可能的,所以這個(gè)時(shí)候就是拉賓米勒算法的表演時(shí)間了。

這篇文章講了一下費(fèi)馬小定理,以及由費(fèi)馬小定理而應(yīng)出的偽素?cái)?shù)和歐拉定理的一些小問題他么的因果關(guān)系,以及最后引出的拉賓米勒算法Miller-Rabin算法素?cái)?shù)與素?cái)?shù)測試, 這篇文章中的防止溢出技巧,我開始都沒當(dāng)回事,直到后來。。。

總結(jié)一哈,最早因?yàn)橛匈M(fèi)馬小定理,所以可以直接用a^(p-1) % p = 1來判斷是否p是素?cái)?shù),但是這個(gè)有點(diǎn)問題就是因?yàn)橘M(fèi)馬小定理的必要不充分性,也就是存在一些合數(shù)使得這個(gè)公式成立,所以我們就多找?guī)讉€(gè)a來判斷,這樣就能降低因?yàn)閭嗡財(cái)?shù)也能讓費(fèi)馬小定理成立的而出現(xiàn)的問題,這就是費(fèi)馬測試。
但是除了偽素?cái)?shù)之外還有一種數(shù)更兇,他能通過所有比他小的a的的費(fèi)馬測試,也就是卡邁克爾數(shù)Carmichael
雖然說概率不是很高但是還是不能接受,所以在費(fèi)馬測試的基礎(chǔ)上又出現(xiàn)了Rabin-Miller素?cái)?shù)測試,它的核心就是再使用費(fèi)馬測試基礎(chǔ)之上,根據(jù)一個(gè)基本公式,這里就用上面那篇文章的內(nèi)容
溜就溜在這個(gè)公式(x+1)(x-1) % p = 0,因?yàn)閤是小于p的(因?yàn)樗械膞都是模p后的結(jié)果),如果p是素?cái)?shù),模p等于0的的數(shù)只有0和p本身,如果是合數(shù),就會可能出現(xiàn)其他的情況
Rabin-MIller算法模板

ll shuzu[9] = {2,3,5,7,11,13,17,19,23}; //ll shuzu[10] = {2, 3, 5, 7,11,31,61,73,233,331};ll mul(ll a, ll b, ll n){ll answer = 0;a %= n;while(b){if(b & 1) answer = (answer + a) % n;a = (a + a) % n;b >>= 1;}return answer; }ll poww(ll a, ll b, ll n){ll answer = 1;a %= n;while(b){ if(b & 1) answer = mul(answer, a, n) % n;a = mul(a, a, n) % n;b >>= 1;}return answer; }bool feima(ll a, ll n, ll k, ll m){ll pre = poww(a, m, n) % n;if(pre == 1)return false;while(k --){ll next = mul(pre, pre, n) % n;if(next==1 && pre!=1 && pre!=n-1) return true; pre = next;} return (pre != 1); }bool isprime(ll n){ll k = 0, m = n - 1;if(n == 2) return true;if(n<2 || !(n&1)) return false;while( !(m&1)) {k++; m >>= 1;} //先把大數(shù)化簡到最小,后面二次探測從小往大判斷,防止溢出for(int i = 0; i < 9; i++){if(n == shuzu[i])return true;if(feima(shuzu[i], n, k, m)) return false;}return true; }

這其中用了兩重快速冪,下面有講解




當(dāng)我在研究Pollard Rho查詢大整數(shù)因子算法的時(shí)候,我想測試一哈一個(gè)大素?cái)?shù),和一個(gè)大合數(shù)在使用Pollard Rho的速度差異(那種17、18位長的數(shù)),然后我自己隨便寫了幾個(gè)循環(huán)用Rabin-Miller判斷是不是素?cái)?shù),結(jié)果找了很久都沒有找到,眾里尋他千百度。。。最后我在網(wǎng)上找大一篇文章,關(guān)于解決快速判斷l(xiāng)onglong型的整數(shù)是否為素?cái)?shù), 他說有一個(gè)18位素?cái)?shù)154590409516822759,然后我就用我剛學(xué)的Rabin-Miller測一了哈,結(jié)果不對!!!

然后經(jīng)過我一番調(diào)試,終于找到了問題的根源,那就是數(shù)據(jù)溢出問題,也就是在使用快速冪懲罰的時(shí)候出現(xiàn)的因?yàn)槿∧5臄?shù)太大比如 1e17 % 1e18 = 1e17,但是如果1e17 * 1e17 % 1e18的時(shí)候就會出現(xiàn)查過了long long的最大數(shù)據(jù)長度,解決這個(gè)問題的辦法很溜,只用把乘法替換成加法,這是你可能會說加法雖然可以沒加一次的時(shí)候取模,但是像1e17 * 1e17循環(huán)下來還是很慢,根本不行啊。普通循環(huán)加法不行就用快速冪加法,輕輕松松就解決了。。

解決快速冪乘法的辦法模板:

ll mul(ll a, ll b, ll n){ll answer = 0;a %= n;while(b){if(b & 1) answer = answer + a % n;a = a + a % n;b >>= 1;} }ll poww(ll a, ll b, ll n){ll answer = 1;a %= n;while(b){if(b & 1) answer = mul(answer, a, n) % n;a = mul(a, a, n);b >>= 1;}return answer; }

以后用快速冪的時(shí)候最后都這樣組合用, 比較穩(wěn)妥,免得數(shù)據(jù)溢出。


Pollard Rho分解因子算法

波拉德算法–Pollard Rho,是用來查找一個(gè)大整數(shù)中的因子,我剛剛學(xué)習(xí)這個(gè)算法的時(shí)候,我看到居然是用隨機(jī)數(shù)來判斷是否能整除的時(shí)候(相當(dāng)于是在猜),感覺很懵。。哪見到過用隨機(jī)出來猜因子的啊,那效率豈不是比用循環(huán)一個(gè)一個(gè)挨到搞還慢,然后就跟在研究玄學(xué)一樣。。。下面的文章很推薦,建議配合研究

大數(shù)質(zhì)因解:淺談Miller-Rabin和Pollard-Rho算法
Rollard Rho文章翻譯

還是隨機(jī)數(shù)的問題,為什么要隨機(jī)數(shù)喃?隨機(jī)數(shù)給我的第一感覺還不如用循環(huán),因?yàn)殡S機(jī)數(shù)又是偽隨機(jī)而且還有可能重復(fù),所以效率肯定低三~。但是,這里的重復(fù)就有點(diǎn)意思了,有個(gè)東西叫做生日悖論,來一張百度百科的圖解
神不神奇,意不意外,玄學(xué)不玄學(xué),但是不管他吹的有好神,時(shí)間是檢驗(yàn)真理的唯一標(biāo)準(zhǔn),一切從實(shí)際出發(fā),理論結(jié)合實(shí)際,實(shí)事求是,在實(shí)踐中檢驗(yàn)真理并發(fā)展真理,寫個(gè)程序驗(yàn)證一哈

#include<iostream> #include<cstdlib> using namespace std; #define maxn 23 int shuzu[maxn];int main(){int ci = 20, year = 365;while(ci --){double success = 0;int jishu = 15; while(jishu -- ){for(int i = 0; i < maxn; i++) shuzu[i] = rand() % year;int flag = 0;for(int i = 0; i < maxn; i++){for(int j = i+1; j < maxn; j++){if(shuzu[i] == shuzu[j]) {flag = 1; break;}}if(flag) break;} if(flag){success ++;cout << "yes" << " "; }else{cout << "no " << " ";}}cout << "幾率:" << success / 15 * 100 << "%" << endl;}return 0; }

雖然說了這么的多的生日悖論,但是我之前感覺在Pollard-Rho算法中其實(shí)也就只是提升了一點(diǎn)幾率,因?yàn)榇蠖鄶?shù)模板(包括維基百科給的代碼),都只是每次生成倆個(gè)隨機(jī)數(shù),然后用這兩個(gè)隨機(jī)數(shù)做差取絕對值,后來我在看別人的文章中都會說是從1, 2, 。。。n-1這些數(shù)中取,因?yàn)槲覀兪侨∧?#xff0c;其實(shí)就相當(dāng)于我們已經(jīng)有了很多人(然后我們只是負(fù)責(zé)從匯總隨便抽取兩個(gè)人來判斷)。而且在實(shí)際中,我們一般都不用隨機(jī)函數(shù),一般用自己定義的一個(gè)生成函數(shù)f(x) = x^2 + c(c是自己定義的一個(gè)常數(shù)),而在不停修改c的過程中,基本上可以遍歷到所有比n小的數(shù)。

但是現(xiàn)在的概率還不夠,還能增加猜中的概率,就是通過gcd,隨便找兩個(gè)比n小的數(shù),他們差得絕對值剛好能被n整除的概率,還是不大,但是如果他們差的絕對值和n有相同的因子,也就是他們的差是n因子的倍數(shù)幾率就又提升了

還有個(gè)問題就是判圈,之前用kruskal的時(shí)候,判斷環(huán)用的是并查集,但是這里好像有點(diǎn)區(qū)別,這里是循環(huán)節(jié)。。。比如說一個(gè)函數(shù)F(x) = (F(x-1)^2 + 1) % 44,而F(0) = 1的時(shí)候,就會出現(xiàn)一個(gè)數(shù)列2, 5, 26, 17, 26, 17, 26, 17, 。。。,可以看出,這個(gè)數(shù)列先經(jīng)過兩個(gè)數(shù),然后就進(jìn)入了一個(gè)圈中,這里借用 Pollard-Rho算法詳解 這篇文章中的圖

也就和希臘字母中的很像,下圖中最右邊那個(gè)字母,不過確實(shí)沒想到這個(gè)算法的名字這么有內(nèi)涵~

這里的圈是一定會出現(xiàn)的,因?yàn)殡S便一個(gè)數(shù)n,只要n已確定,那么小于n的正整數(shù)就是有限的,在取模的時(shí)候,只要在某次運(yùn)算后,與之前的某個(gè)數(shù)相同,就進(jìn)入了圈。

Pollard-Rho算法判圈
所以現(xiàn)在最后一個(gè)問題就是要解決這個(gè)圈的問題,也就是怎么讓唐僧走出這個(gè)圈,我現(xiàn)在了解到有兩種判圈,一種是floyd,一種是brent,感覺floyd的講解信息最多,但是我在網(wǎng)上搜Pollard-Rho算法模板,大家基本上都用的是brent,而且我感覺用floyd有一個(gè)問題,那就是當(dāng)判斷數(shù)是4的時(shí)候,雖然判圈是對的,但是沒法讓a和b的差剛好等于2(4除了1和本身之外只有2這個(gè)唯一的因子)也就是要讓a和b分別等于0、2或者1、3,但是弗洛伊德判圈是讓b推導(dǎo)的速度是a的兩倍,也就是說他們兩個(gè)會錯(cuò)過很多組合。。。我也沒搞醒活,我只是在運(yùn)行的時(shí)候遇到這個(gè)問題。而且網(wǎng)上很多的模板基本上都沒有用弗洛伊德,用的是brent,這個(gè)確實(shí)也玄學(xué),反正感覺不是很清楚,目前也就維基百科上面我看到的講解最多Brent’s algorithm

Pollar-Rho算法模板:

ll absabs(ll input){if(input < 0) input *= -1;return input; }ll gcd(ll a, ll b){ll c = a % b;while(c){a = b;b = c;c = a % b;}return b; }ll find_factor(ll n, ll c){ll a = 2, b = a, i = 0, k = 1;while(1){i ++;a = (mul(a, a, n) + c ) % n;ll p = gcd(absabs(a-b), n);if(p!=1 && p!=n) return p;if(a == b) return -1; if(i == k){b = a;k <<= 1;}} }void find(ll n, ll c){ if(n==1 || isprime(n)){shuzu[length++] = n;return ;}ll temp = -1;ll cc = c;while(temp == -1) temp = find_factor(n, cc--); find(temp, c);find(n / temp, c); }

這個(gè)大整數(shù)123456789123456798用來測試Pollard-Rho算法還可以

篩選素?cái)?shù)

最出名的,埃氏篩,模板

void init(){memset(shuzu, 0, sizeof(shuzu));for(int i = 2; i < maxn; i++){if(!shuzu[i]) shuzu[++shuzu[0]] = i;for(int j = 1; j<=shuzu[0] && i*shuzu[j]<maxn; j++){shuzu[i*shuzu[j]] = 1;}}// for(int i = 0; i < 100; i ++) cout << shuzu[i] << " "; cout << endl; }

poj3978直接用埃氏篩

有些時(shí)候求一個(gè)區(qū)間的素?cái)?shù),并不會從0開始,或者很大的時(shí)候,會用到容斥原理,我這里就只記錄埃氏篩法,直接上書上的講解

poj2689
就是照著上圖的講解

#include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; #define maxn 46345 typedef struct Node{int qian, hou;int dist;void update(int q, int h, int d){qian = q;hou = h;dist = d;} }Node; Node jin, yuan; int shuzu[maxn];void init(){memset(shuzu, 0, sizeof(shuzu));for(int i = 2; i < maxn; i++){if(!shuzu[i]) shuzu[++shuzu[0]] = i;for(int j = 1; j<=shuzu[0] && i*shuzu[j]<maxn; j++){shuzu[i*shuzu[j]] = 1;}}// for(int i = 0; i < 100; i ++) cout << shuzu[i] << " "; cout << endl; }int maxmax(int a, int b, int c){int temp = a / b;if(a % b != 0) temp ++;return temp > c ? temp : c; }int arr[1000005]; void getprime(int start, int end){ memset(arr, 0, sizeof(arr)); for(long long i = 1; i<=shuzu[0] && shuzu[i]*shuzu[i]<=end; i++){ //注意這里初始化的時(shí)候如果不判斷是否除的盡,后面就會產(chǎn)生素?cái)?shù) for(long long j = maxmax(start, shuzu[i], 2); j*shuzu[i]<=end; j++){arr[j*shuzu[i]-start] = 1; } }int qian = -1; jin.dist = 0x7FFFFFFF;yuan.dist = 0;for(int i = 0; i < end-start+1; i++){ if(!arr[i]){if(qian == -1) qian = i;else{if(i-qian < jin.dist) jin.update(qian+start, i+start, i-qian);if(i-qian > yuan.dist) yuan.update(qian+start, i+start, i-qian);}qian = i;}}if(jin.dist == 0x7FFFFFFF) cout << "There are no adjacent primes." << endl;elseprintf("%d,%d are closest, %d,%d are most distant.\n", jin.qian, jin.hou, yuan.qian, yuan.hou); }int main(){ int start, end;init(); while(~scanf("%d%d", &start, &end)){if(start == 1) start ++;getprime(start, end);}return 0; }/* 2146483647 2147483647*/

總結(jié)

以上是生活随笔為你收集整理的数论入门的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。