【藍橋杯真題-線性素數法+列舉法】等差素數列
阿新 • • 發佈:2019-02-07
(程式碼原po):
#include <algorithm>
#include
<string.h>#include <iostream>#include <stdio.h>#include
<string>#include <vector>#include <queue>#include
<map>#include <set>using
namespace
std;const
long
long N = 1000010;int dp[N]={1,1,0};int
prim[N],tot = 0 ;void init(){
for(long
long i =
2 ; i < N ; i ++) {
if(dp[i])continue; prim[tot++]=i;
for(long
long j = i ; j * i < N ; j ++){ dp[i*j] =
1; } }}int main(){ init();
printf("%d\n",tot);
for(int i =
1 ; i*10 < N ; i ++){
for(int j =
0 ; j < tot ; j ++){
int flag =
1,temp = prim[j];
for(int k =
1 ; k <
10 ; k ++) { if(temp + i >= N || dp[temp + i] ==
1){ flag =
0;break; }else{ temp = temp + i; } }
if(flag ==
1){ printf("%d %d\n",i,prim[j]);
return
0; } } } return
0;}//210 199
學到的點:
①首先,這道題應該去求全體素數序列(到1000000即可),用到“線性素數法”(很快地找全體素數),程式碼如下:
- constint M = 3000500;
- int p[400010], pNum;
- bool f[M];
-
void
- {
- int i, j;
- for(i = 2; i < M; i++) {
- if(!f[i]) { p[pNum++] = i; }
- for(j = 0; j < pNum && p[j] * i < M; j++ ) {
- f[p[j]*i] = 1;
- if(!(i%p[j]))
- break;
- }
- }
- }
舉個例子:
比如i = 9,現在素數是2 3 5 7
進入第二重迴圈了,f[2 * 9] = 1;f[3 * 9] = 1;
這個時候9%3==0,要跳出了,為什麼不做f[5* 9] =1;呢?
因為5 * 9 可以用3 * 15來代替,如果這個時候你計算了,那麼到i=15的時候這個數還會被重複計算一次,所以這裡大量避免了重複運算,所以也就節省了時間。
這裡總結一句話就是,一個大的合數和這個能除盡的質數的乘積,一定能被一個比起小的質數和合數更大的合數乘積來代替。
不懂的時候想想 5*9 = 5*3*3 = 3*15就是這個道理。
這也是線性篩法算質數表的關鍵所在。
②學到枚舉了。暴力列舉其實沒有想象中那麼簡單,一定是要結合題意,就算是列舉,也是需要在for語句中根據題意增加一些約束條件的。
比如這裡,10個數的(遞增)等差數列的公差*10一定<最大數,然後就是找起點,對於每個起點去依次迭加公差,每一次的迭加都要符合
是素數的條件並且小於1000000(注意&& || 別用混。。)。
(對每一個起點)迭加九次,比較關鍵的地方在於用flag去判斷迴圈結束後這個迴圈滿足條件不,滿足,flag仍=1,那麼
這個公差即所求。
PS:後半部分自己寫的程式碼是
for(int k=1;k*10<1000000;k++) { for(int i=0;i<pos;i++) { int flag=1; int temp=prim[i]; for(int j=0;j<9;j++) { if(temp+k>=1000000 || f[temp+k]==1) { flag=0; break; } else{ temp=temp+k; } } if(flag==1) {cout<<k<<endl; return 0; } } } return 0;}
執行出來不對,不知道為何。暫時擱著(...ε=(´ο`*)))唉)