Count primes

问题:

求解[1~n]中质数个数,质数之和。

 

解法:

大于2的正整数 $n$ 为质数当且仅当 对于任何 $p∈{Prime}, p \leq [\sqrt n] $ 都有 $n \ mod \ p \neq 0$

这样我们有效的 $p$ 最多有大约400000个。

考虑$dp$

$S(n,m)$,表示 1~n 的数字,用前m个质数筛完后剩余的数字的和。

$F(n,m)$,表示 1~n 的数字,用前m个质数筛完后剩余的数字个数。

这样有

$$F(n,m) = F(n,m-1) - F(\frac{n}{p_m},m-1) + F(p_m-1,m-1), p_m^2 \leq n$$

$$F(n,m) = F(n,m-1), p_m^2 > n$$

$$S(n,m) = S(n,m-1) - p_m \cdot (S(\frac{n}{p_m},m-1) + S(p_m-1,m-1)), p_m^2 \leq n$$

$$S(n,m) = S(n,m-1), p_m^2 > n$$

预处理出 n,m 较小时的情况即可。

 

#include <bits/stdc++.h>

#define LL long long

using namespace std;

typedef pair<LL,int> PII;

const int N = 3000010;

int prime[N],tot,tim_cnt;
LL f[10010][110];
bool v[N];

LL calc(LL n,int m)
{
    if(n==0LL) return 0;
    if(m==0) return n;
    if(n<10010LL && m<110) return f[n][m]; 
    if(prime[m]*(LL)prime[m] > n)
    {
        int t = m-1;
        while(t && prime[t]*(LL)prime[t] > n) t--;
        return calc(n,t);
    }
    return calc(n,m-1) - calc(n/(LL)prime[m], m-1) + calc(prime[m]-1LL,m-1);
}

LL calc(LL n)
{
    int m;
    tim_cnt = 0;
    for(m=0;prime[m+1]*(LL)prime[m+1] <= n;m++);
    return calc(n,m)-1LL;
}

void init()
{
    memset(f,0,sizeof(f));
    for(int i=0;i<10010;i++)
        for(int j=0;j<110;j++)
        {
            if(i==0) f[i][j]=0;
            else if(j==0) f[i][j] = i;
            else if(prime[j]*(LL)prime[j] > i) f[i][j] = f[i][j-1];
            else f[i][j] = f[i][j-1] - f[i/prime[j]][j-1] + f[prime[j]-1][j-1];
        }
}

int main()
{
//    int T;
//    cin>>T;
    LL n;
    for(int i=2;i<N;i++)
        if(!v[i])
        {
            prime[++tot] = i;
            for(int j=i+i;j<N;j+=i) v[j]=1;
        }
    init();
    while(cin>>n)
    {
    //    cin >> n;
        tim_cnt = 0;
    //    double now = clock()/1000.0; 
        cout << /*"cnt = " <<*/ calc(n) << endl;
//        cout << "time = " << clock()/1000.0 - now << " times "<< tim_cnt << endl;
    }
    return 0;
}
View Code

 

posted @ 2017-06-01 16:07  lawyer'  阅读(173)  评论(0编辑  收藏  举报