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