USACO1.5Superprime Rid[附帶關於素數演算法時間測試]

Candy?發表於2016-08-19

題目描述

農民約翰的母牛總是產生最好的肋骨。你能通過農民約翰和美國農業部標記在每根肋骨上的數字認出它們。農民約翰確定他賣給買方的是真正的質數肋骨,是因為從右邊開始切下肋骨,每次還剩下的肋骨上的數字都組成一個質數,舉例來說: 7 3 3 1 全部肋骨上的數字 7331是質數;三根肋骨 733是質數;二根肋骨 73 是質數;當然,最後一根肋骨 7 也是質數。 7331 被叫做長度 4 的特殊質數。寫一個程式對給定的肋骨的數目 N (1<=N<=8),求出所有的特殊質數。數字1不被看作一個質數。

輸入輸出格式

輸入格式:

單獨的一行包含N。

輸出格式:

按順序輸出長度為 N 的特殊質數,每行一個。

輸入輸出樣例

輸入樣例#1:
4
輸出樣例#1:
2333
2339
2393
2399
2939
3119
3137
3733
3739
3793
3797
5939
7193
7331
7333
7393

說明

題目翻譯來自NOCOW。

USACO Training Section 1.5

-----------------------------

第一位一定是2,3,5,7 ,以後各位只能是單數,並且不能是5,直接dfs每一位,只要不是prime就退出

用哪個方法判素數呢?

一開始隨手打了尤拉篩法,結果MLE+TLE,又改了個樸素演算法,結果AC了....

對於n等於8,其實只有4^8=65536次檢測,太少了,即使根號n的複雜度,合起來是16777216,尤拉篩法卻要10^8

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

於是我開始測速玩,測試環境MacBook Air13

n=1e8,我實現的Euler篩法要跑1.3s左右,Eratosthenes篩法要近3s......然而,樸素竟是1.1s,Miller-Rabin只要0.5s;

Miller-Rabin完虐Euler篩法暫且不說,為什麼樸素方法也比Euler篩法快,O(n根號n)與O(n)沒法比吧..........這是玄學

n=1e6,Eratosthenes篩法0.5s,Euler篩法0.016s,樸素也在0.016s左右,Miller-Rabin只要0.01s

這是要Eratosthenes篩法情何以堪

------------------------------------------------------------------------------------------------------------------------------------------------------------

[2016-08-19更新]:

都是memset惹的禍,去掉後Eratosthenes n=1e8是2.26s,n=1e6可以0.021s,樸素也是0.021,然而Euler篩法卻0.026s還是玄學

 

------------------------------------------------------------------------------------------------------------------------------------------------------------

 

 上面說的太亂了,總結一下:

分別是n=1e8 n=1e6

樸素 1.2s 0.03s

Eratosthenes篩法 2.26s 0.021s

Euler篩法 1.4s 0.016s

Miller-Rabin 0.5 0.01

 

 

//
//  main.cpp
//  usaco1.5 superprime rib
//
//  Created by abc on 16/8/15.
//  Copyright © 2016年 abc. All rights reserved.
//

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int N=1e8+5,L=10;

int n=1,l;
//bool flag[N];int prime[N];
int st[4]={2,3,5,7},odd[4]={1,3,7,9},a[L];
//int es(int n){
//    int cp=0;
//    for(int i=2;i<=n;i++){
//        if(!flag[i]) prime[++cp]=i;
//        for(int j=1;j<=cp&&prime[j]*i<=n;j++){
//            flag[i*prime[j]]=1;
//            if(i%prime[j]==0) break;
//        }
//    }
//    return cp;
//}
inline int flag(int n){
    int m=sqrt(n)+1;
    for(int i=2;i<=m;i++) if(n%i==0) return 1;
    return 0;
}
void dfs(int now,int v){//cout<<now<<"\n";
    if(now==l+1){
        for(int i=1;i<=l;i++) printf("%d",a[i]);
        printf("\n");
        return;
    }
    for(int i=0;i<4;i++){
        a[now]=odd[i];
        if(flag(v*10+a[now])==0) dfs(now+1,v*10+a[now]);
    }
}
int main(int argc, const char * argv[]) {
    cin>>l;
    for(int i=1;i<=l;i++) n=10*n;
    //es(n);
    for(int i=0;i<4;i++){
        memset(a,0,sizeof(a));
        a[1]=st[i];
        dfs(2,st[i]);
    }
    return 0;
}

 

相關文章