素数与线性筛选法初级版
今天我們來學習一些關于素數和線性篩選法的知識,這類問題在ACM-ICPC中常常遇到,所以很有必要學好它。
?
首先,來看素數篩選的一個題。
?
題目:http://codeforces.com/problemset/problem/114/E
?
題意:給定區間,在這個區間里有多少個素數,使得成立,其中。
?
分析:由費馬平方和定理知道,一個奇素數能表示為兩個數的平方和,那么這個奇素數一定是型的。那么
???? 只需要先篩選出所有素數,然后一個一個判斷即可,但是這個區間可能很大。普通的素數篩選法是用bool數
???? 組,占一個字節空間,這樣很耗費內存,實際上在C++中有一個神器叫做bitset,它是以位為單位的。
?
代碼:
#include <iostream> #include <string.h> #include <stdio.h> #include <bitset>using namespace std; const int N = 300000005;bitset<N> prime;void Work(int l,int r) {prime.set();for(int i=3; i*i<=r; i+=2){if(prime[i]){for(int j=i*i; j<=r; j += i<<1)prime[j] = false;}}int cnt = (l <=2 && 2 <= r);for(int i=5; i<=r; i+=4)if(i >= l && prime[i]) cnt++;cout<<cnt<<endl; }int main() {int l, r;cin>>l>>r;Work(l,r);return 0; }
?
題目:http://acm.hdu.edu.cn/showproblem.php?pid=1999
?
題意:設是正整數的所有真因子之和,如果對于任何的,都不等于,那么稱為不可模數。
???? 輸入一個正整數,判斷它是否是不可模數。
?
分析:可以先用線性篩選法求出的每個數的真因子之和,然后再預處理。
?
代碼:
#include <iostream> #include <string.h> #include <stdio.h>using namespace std; const int N = 1000005;int sum[N]; bool ok[1005];void Init() {memset(ok,0,sizeof(ok));for(int i=1;i<N;i++)for(int j=i+i;j<N;j+=i)sum[j] += i;for(int i=1;i<N;i++)if(sum[i] < 1005)ok[sum[i]] = 1; }int main() {Init();int T;scanf("%d",&T);while(T--){int n;scanf("%d",&n);if(ok[n]) puts("no");else puts("yes");}return 0; }
題目:http://acm.hdu.edu.cn/showproblem.php?pid=3823
?
題意:給定兩個數和,找一個最小的,使得和是兩個相鄰的素數,其中。
?
代碼:
#include <iostream> #include <string.h> #include <stdio.h> #include <bitset>using namespace std; const int N = 20000005;bitset<N> prime; int p[N]; int cnt; bool ok[155];void isprime() {cnt = 0;prime.set();for(int i=2; i<N; i++){if(prime[i]){p[cnt++] = i;for(int j=i+i; j<N; j+=i)prime[j] = false;}} }int main() {isprime();memset(ok,0,sizeof(ok));for(int i=1;i<cnt;i++){if(p[i] - p[i-1] <= 150)ok[p[i] - p[i-1]] = 1;}int T, a, b, t = 1;scanf("%d",&T);while(T--){scanf("%d%d",&a,&b);if(a > b) swap(a, b);printf("Case %d: ",t++);if(!ok[b - a] || a == b){puts("-1");continue;}int k = -1;for(int i=1; i<cnt; i++){if(p[i] - p[i-1] == b - a && p[i-1] >= a){k = i;break;}}if(k == -1) puts("-1");else printf("%d\n",p[k] - b);}return 0; }
?
題目:http://acm.hdu.edu.cn/showproblem.php?pid=2136
?
題意:給定一個數,求它的最大素因子在素數表中排列第幾。
?
分析:由于輸入很多,所以用篩選法預處理。
?
代碼:
#include <iostream> #include <string.h> #include <stdio.h>using namespace std; const int N = 1000005;int Rank[N];void Init() {int cnt = 1;for(int i=2;i<N;i++){if(Rank[i]) continue;for(int j=i;j<N;j+=i)Rank[j] = cnt;cnt++;} }int main() {int n;Init();while(scanf("%d",&n)!=EOF)printf("%d\n",Rank[n]);return 0; }
題目:http://acm.tzc.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=3349
?
題意:給定個正整數,范圍均在以內,對于每一個數都找出剩下的數中有多少個是它的倍數。
?
代碼:
#include <iostream> #include <string.h> #include <stdio.h>using namespace std; const int N = 1000005;int cnt[N]; int a[N]; int ans[N];void Work(int n) {int max = 0;for(int i=1; i<=n; i++){scanf("%d",&a[i]);cnt[a[i]]++;if(max < a[i])max = a[i];}for(int i=1; i<=max; i++){if(cnt[i]){for(int j=i+i; j<=max; j+=i)ans[j] += cnt[i];}}for(int i=1; i<=n; i++){if(cnt[a[i]] > 1) printf("%d\n",ans[a[i]] + cnt[a[i]] - 1);else printf("%d\n",ans[a[i]]);} }int main() {int n;scanf("%d",&n);Work(n);return 0; }?
?
?
總結
以上是生活随笔為你收集整理的素数与线性筛选法初级版的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HDU4357(数学思维题)
- 下一篇: HDU4364(模拟矩阵乘法)