国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

素數篩法系列

2019-11-08 03:08:59
字體:
來源:轉載
供稿:網友

本目主要整理素數篩法的若干技巧。

思路

首先需要一個性質:

合數必有素因子

其次,圍繞這個定理可以展開相關證明。那么,當再需要判斷一個數是否是素數的時候,只需判斷它能不能被這些素因子整除。若可以,則不為素數,即為合數。反之,則是素數。

當有了上面的思路之后,我們進步一步的換一個角度,既然所有合數都有素因子,那么當我們獲得一個素數時,可以把它的倍數全部標記為合數。這樣,當我們判斷某一個數是否為素數時,只需判斷它是否被標記過即可。這就是素數篩法的大致思想。

問題1

[jobdu-1163]

思路

常規的辦法不說了,下面主要說一下素數篩法的系列。

代碼

#include <iostream>#include <cstring>const int maxn = 10000;bool mark[maxn + 8]; // mark[i]==true表示非素數,標記的是素數的倍數,都是合數。int PRime_table[maxn + 8];int prime_cnt;void init(){ std::memset( mark, 0, sizeof(mark) ); for(int i = 2; i <= maxn; ++i ){ if(mark[i]) continue; // 非素數 else{ // 加入素數 prime_table[prime_cnt++] = i; // 標記非素數 for(int j = i*i; j <= maxn; j += i){ mark[j] = true; } } }}int main(){ int n; init(); while(std::cin >> n){ bool first = true; for(int val = 2; val < n; ++val){ if(!mark[val] && val%10==1){ if(first){ std::cout << val; first = false; } else std::cout << " " << val; } } if(first) std::cout << -1 << std::endl; else std::cout << std::endl; } return 0;}

上面的代碼需要注意一點:下面這段標記代碼,應該是把素數i的倍數全部標記為合數,應該是int j = i*2; j <= maxn; j+=i開始。但是,j = i*i的原因在于,對于任意k < i, int j = i*k,當k是素數的時候,j就已經被標記過了,所以沒有必要重復標記。注意即可。

// 加入素數 prime_table[prime_cnt++] = i; // 標記非素數 for(int j = i*i; j <= maxn; j += i){ mark[j] = true; }

題目2

[jobdu-1047]

思路

素數篩法即可。

代碼

#include <iostream>#include <cstring>#include <climits>const unsigned maxn = 1024;bool mark[maxn + 1];void init(){ std::memset( mark, 0, sizeof(mark) ); for(int i = 2; i < maxn; ++i){ if(mark[i]) continue; else{ for(int j = i*i; j<= maxn; j +=i){ mark[j] = true; } } }}int main(void){ int val = 0; init(); while(std::cin >> val){ if(val < 2) std::cout << "no" << std::endl; else if(mark[val]) std::cout << "no" << std::endl; else std::cout << "yes" << std::endl; } return 0;}

問題3

參看以下這篇鏈接, 這是leetcode的問題。有一些和上面不同的問題。[Count Primes]

問題4(分解素因數)

[jobdu-1207]

思路

開心!這個題之前都沒有用素數篩法做對過。 思路沒什么好說的,只不過這個題引入了一個新的問題是:分解素因數 這依賴于定理:

合數一定可以分解為素因子相乘的形式

根據這個定理,我們知道對于一個合數可以全部分解為素因子的形式。那么本體的問題就是求解這個分解表達式,即對于任意一個數x,分解為如下的形式:其中p1,p2,?pn均為素數。

x=pe11?pe22…penn

代碼的思路并不難,要是拿到素數表之后,挨個除即可。 但是有個問題是,這個素數表,你要開多大?

那么需要如下的定理來解決這個問題,:

對于任意一個數x,其大于x√的素因子至多為1個。

否者,這兩個大于x√的因子相乘肯定是要大于x的。 所以,對于邊界 N = 1000000000。我們只需找到小于N??√的素因子即可。如果一個數在除過以上的素因子之后沒有變成1,那么證明它還有一個大素因子,此時在最后的結果 + 1即可。

所以,素數表空間的開辟,我們選擇maxn =100000,這就是為什么要這么寫的原因。 還有第二個點要說的是,對于int j = i*i,當i = maxn的時候,j是會越界的。所以,建議還是改用之前的形式。int j = i*2。其實,早上那道題,也是這里修改之后才過的。

出了一個小bug是:index < prime_cnt這個條件寫錯了。如果存在大素因子,這樣數組不就越界了。

代碼

#include <iostream>#include <cstring>const int maxn = 100000;bool marker[maxn+1];int prime_cnt;int prime_table[maxn+1];void init(){ std::memset(marker, 0, sizeof(marker)); prime_cnt = 0; for(int i = 2; i <= maxn; ++i){ if(marker[i]) continue; else{ prime_table[prime_cnt++] = i; for(int j = i*2; j <= maxn; j += i){ marker[j] = true; } } }}int main( void ){ int n = 0; init(); while(std::cin >> n){ int ans = 0; int index = 0; while(n != 1 && index < prime_cnt){ while(n!= 1 && n % prime_table[index] == 0) { ++ans; n /= prime_table[index]; } ++index; } if(n!=1) ++ans; // 存在大素因子 std::cout << ans << std::endl; } return 0;}

問題4(ugly number)

參考這篇鏈接:[ugly number] 有兩個注意點:

輔助空間大小的開辟大素因子的判斷
上一篇:Crackme 2

下一篇:475. Heaters

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 舞阳县| 和平区| 瑞丽市| 松江区| 子长县| 灯塔市| 女性| 隆安县| 南投县| 威海市| 陇南市| 英吉沙县| 驻马店市| 桦川县| 灯塔市| 通州区| 工布江达县| 阿拉善左旗| 二连浩特市| 灵石县| 乐昌市| 南溪县| 甘孜县| 玉山县| 石棉县| 嘉定区| 阳西县| 哈巴河县| 平昌县| 崇左市| 榕江县| 右玉县| 泰州市| 蛟河市| 巴林右旗| 苍山县| 武鸣县| 本溪市| 铜梁县| 安阳县| 日土县|