Project Euler 712
题目
Exponent Difference
For any integer $n>0$ and prime number $p,$ define $\nu_p(n)$ as the greatest integer $r$ such that $p^r$ divides $n$.
Define For example, $D(14,24) = 4$.
Furthermore, define You are given $S(10) = 210$ and $S(10^2) = 37018$.
Find $S(10^{12})$. Give your answer modulo $1\,000\,000\,007$.
Lehmer公式
Lehmer公式给出了质数计数函数$\pi$的一个计算方式:
其中,$p_i$表示第$i$个质数,$a=\pi(\sqrt[4]{x}),b=\pi(\sqrt{x}),c=\pi(\sqrt[3]{x}),b_i=\pi\left(\sqrt{\dfrac{x}{p_i}}\right)$
其中$\varphi(x,a)$是$n$以内的数中,质因数只由第$a+1$个及以后的质数的个数,用容斥原理可以写成:
为了方便计算,页面)说明$\varphi(x,a)$还可以写成以下递推式形式:
在计算函数$\pi$和$\varphi$时,需要使用记忆化方法记录函数值。
解决方案
本解决方案参考了Thread中的一些内容。
令$N=10^{12}$。不难想到,单独考虑每一个的质数$p$,求取它们的贡献并相加。
假设质数集合为$P$。我们考虑将$N$以内的质数分成两部分考虑:小于等于$\lfloor\sqrt{N}\rfloor$和大于$\lfloor\sqrt{N}\rfloor$的两部分。
小于等于$\lfloor\sqrt{N}\rfloor$的质数$p$这一部分贡献为:
其中,上面的式子可以化简:
那么计算以下式子只需要计算$O(\sqrt{N}\cdot \log N)$的时间复杂度:
大于$\lfloor\sqrt{N}\rfloor$的质数$p$这一部分贡献如下。注意到,$1\sim N$中,$p$的指数最多为$1$:
这条式子说明,有$\pi\left(\dfrac{N}{i-1}\right)-\pi\left(\dfrac{N}{i}\right)$个质数$p$,满足$1\sim N$中有$i-1$个数是$p$的倍数,它们的贡献为$(i-1)(N-i+1)$。
计算函数$\pi$考虑使用Lehmer公式帮助计算。
代码
本代码效率略低,约$30s$,仍有很大改进空间。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| #include <bits/stdc++.h> using namespace std; typedef long long ll; const ll N = 1000000000000; ll mod=1000000007; const ll M = N<=10000?10000:pow(N, 2.0 / 3) + 2; bool vis[M + 1]; int sum[M + 1],pr[M + 1],m; unordered_map<ll,ll> mp,mq; ll phi(ll x, ll a) { if (a == 1 || x == 0)return (x + 1) / 2; ll &v = mp[(x << 10) + a]; if (v)return v; return v = phi(x, a - 1) - phi(x / pr[a], a - 1); } ll pi(ll n) { if (n <= M)return sum[n]; ll &v = mq[n]; if (v) return v; ll a = pi(pow(n, 1.0 / 4)); ll b = pi(sqrt(n)); ll c = pi(pow(n, 1.0 / 3)); ll s = phi(n, a) + (b + a - 2) * (b - a + 1) / 2; for (ll i = a + 1; i <= b; i++) { ll w = n / pr[i]; s -= pi(w); ll bi = pi(sqrt(w)); if (i <= c) { for (ll j = i; j <= bi; j++) s += j - 1 - pi(w / pr[j]); } } return v = s; } ll cal(ll p){ ll ans=0; for(ll x=N/p;x;x/=p){ ans=(ans+x%mod*((N-x)%mod))%mod; } return ans*2%mod; } int main() { for (ll i = 2; i <= M; i++) { if (!vis[i]) { for (ll j = i * i; j <= M; j += i) vis[j] = 1; pr[++m] = i; } sum[i] = m; } ll ans=0; for(int i=1;i<=m&&1ll*pr[i]*pr[i]<=N;i++) ans=(ans+cal(pr[i]))%mod; for(int i=2;1ll*i*i<=N;i++) ans=(ans+(N-i+1)%mod*(i-1)%mod*((pi(N/(i-1))-pi(N/i))%mod)*2%mod)%mod; printf("%lld\n",ans); }
|