1. 程式人生 > >【藍橋杯真題-線性素數法+列舉法】等差素數列

【藍橋杯真題-線性素數法+列舉法】等差素數列

(程式碼原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即可),用到“線性素數法”(很快地找全體素數),程式碼如下:
  1. constint M = 3000500;  
  2. int p[400010], pNum;  
  3. bool f[M];  
  4. void
     Prime()  
  5. {  
  6.     int i, j;  
  7.     for(i = 2; i < M; i++) {  
  8.         if(!f[i]) { p[pNum++] = i; }  
  9.         for(j = 0; j < pNum && p[j] * i < M; j++ ) {  
  10.             f[p[j]*i] = 1;  
  11.             if(!(i%p[j]))  
  12.                 break;  
  13.         }  
  14.     }  
  15. }  
這其實比原Po給的程式碼還要快。因為:最後一個if語句中,

舉個例子:

比如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;}


執行出來不對,不知道為何。暫時擱著(...ε=(´ο`*)))唉)