1. 程式人生 > >一道素數打表的水題,順便記下打表高效方法

一道素數打表的水題,順便記下打表高效方法

codeforces round 388 div2的A題
A. Bachgold Problem

題意問輸入的n最有有多少個素數加起來組成,素數可以重複使用,那這題用貪心,從2開始算起,因為你要求素數最多的話,肯定是越小的個數越多,做完之後,突然發現根本不用打表,n>=2,要麼是奇數,要麼是偶數,偶數就全2,奇數就把一個2換成3就可以了,居然如此簡單。。。。但當時做的時候真的是閃出來素數打表,這就是不用腦地套用習慣思維啊,應該每道題好好地去分析題目特性。

第一次做AC程式碼

#include <iostream>
#include <cstring>
using
namespace std; typedef long long int ll; const int maxn = 100005; bool p[maxn];//0 means prime int primeNum[maxn]; void setPrime() { memset(primeNum,0,sizeof(primeNum)); memset(p,0,sizeof(p)); for(ll i=2;i<maxn;++i){ if(!p[i]){ for(ll j=i*i;j<maxn;j+=i)p[j]=1; } } } int
main() { setPrime(); int n; scanf("%d",&n); int ans = 0; for(int i=2;i<=n;++i){ if(!p[i] && n-i>=0){ primeNum[i] = n/i; ans = ans + primeNum[i]; n = n- n/i*i; } } if(n>0){ if(primeNum[n]){ ans++; primeNum[n]++; }else
{//n==1 primeNum[2]--; primeNum[3]++; } } printf("%d\n",ans); for(int i=2;i<maxn;++i){ while(primeNum[i]--) printf("%d ",i); } printf("\n"); return 0; }

發現奇偶規律之後,從打表變成了線性時間

#include <iostream>
using namespace std;
typedef long long int ll;
const int maxn = 100005;
int main()
{
    int n;
    scanf("%d",&n);
    int ans = n/2;
    printf("%d\n",ans);
    int two = n/2,three = 0;
    if(n%2)two--,three++;
    while(two--)printf("2 ");
    while(three--)printf("3 ");
    printf("\n");
    return 0;
}

時間從31ms變成了30ms????難道是printf慢嗎?,有興趣的朋友可以改用putchar試試。

既然說到了素數打表,順便記錄一下網上的接近線性的高效打表方法

#include<iostream>
#include<string.h>
#include<stdio.h>
#define maxn 10000000
bool visit[maxn+1000000];
int prime[maxn],n; //prime的大小大概估計一下再開陣列。大概是(x/lnx)
void getprime()
{
     memset(visit, false, sizeof(visit));
     int num = 0;
     for (int i = 2; i <= n; ++i)
     {
         if ( !visit[i] )  prime[++num] = i;
         for (int j = 1; (j <= num) && (i * prime[j] <= n) ;  j++)
         {
             visit[ i  *  prime[j] ]  =  true;
             //由 i 和 prime[j] 相乘組成的合數賦為true,注意i不一定為素數,但prime[j] 是素數
             if (i % prime[j] == 0) break; 
             /*此處是重點,避免了很多的重複判斷,比如i=9,現在素數是2,3,5,7,進入二重迴圈,visit[2*9]=1;visit[3*9]=1;這個時候9%3==0,要跳出。因為5*9可以用3*15來代替,如果這個時候計算了,i=15的時候又會被重複計算一次,所以這裡避免了重複大量運算。*/
         }
      }
}
int main()
{
    scanf("%d",&n);
    getprime();
    return 0;
}