题目链接
题目描述
算数基本定理,又称唯一分解定理,算术基本定理可表述为:任何一个大于1的自然数 N,如果N不为质数,那么N可以唯一分解成有限个质数的乘积。即 $N=p_1^{e_1}\cdot p_2^{e_2}…p_m^{e_m}(p_1 < p_2< … p_m)$ 朴素的质因子分解算法就是利用了算数基本定理,依次枚举 $p$ 判断N是否包含素因子 $p$。
牛牛最近对于质因数分解产生了浓厚的兴趣。
牛牛定义了一个函数 $F(x)$,它表示将 $x$ 做质因数分解后得到的数字从小到大升序排列,然后将其“拼接”成一个大整数。
例如 $1500=22355*5,F(1500)=223555$。
牛牛现在想要知道 $\sum_{i=2}^{n}F(i)$ 的值。
由于这个结果非常大,所以你只用告诉牛牛最终答案对 $10^9+7$ 取余数的结果即可。
输入描述:
仅一行一个正整数 $n(2 \leq n \leq 4 \times 10^6)$
输出描述:
仅一行,表示答案对 $10^9+7$ 取余数的结果。
示例1
输入
输出
示例2
输入
输出
一开始就想着暴力算,素筛+质因子分解,这样写跑 $4e6$ 本地要 $3$ 秒,自闭了一会儿我就去忙别的了,最后一个小时突然觉悟了,为什么不记忆化一下每一次算得的答案呢,比如我们暴力算 $20$ 的时候,要算出它所有的质因子:
而记忆化的时候我们只需要算 $2*10^{cnt[ans[10]]}+ans[10]$ 即可,什么意思呢?我们记忆化的时候存两个值,一个是 $ans$ (记录某个数算得的答案),一个是 $cnt$ (记录某个数答案的位数),我们只需要遍历一遍 $n$ 直接算出所有答案即可,递推公式如下:
为了方便计算我还是选了素筛,把 $j$ 替换成了素数,这样复杂度就是线性筛+一次遍历,一共 $O(2N)$,上面公式直接算也可以,复杂度稍高,应该是 $O(NlogN)$,AC代码如下:
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 58 59 60 61 62 63
| #include<bits/stdc++.h>
using namespace std; typedef long long ll;
const ll N = 4e6 + 10; const ll mod = 1e9 + 7; ll n, k, sum, prime[N / 10], cnt[N], ans[N], vis, p10[1000]; bool isprime[N];
ll f(ll x) { ll num = 0; while (x) { num++; x /= 10; } return num; }
void Prime() { fill(isprime, isprime + N, 1); k = 0; for (int i = 2; i <= N; i++) { if (isprime[i]) { prime[k++] = i; } for (int j = 0; j < k; j++) { if (i * prime[j] > N) break; isprime[i * prime[j]] = 0; if (i % prime[j] == 0) break; } } }
void init() { p10[0] = 1; for (ll i = 1; i < 1000; i++) p10[i] = 10 * p10[i - 1] % mod; }
int main() { cin >> n; init(); Prime(); for (int i = 1; i <= n; i++) { for (int j = 0; j < k; j++) { if (i * prime[j] > n) break; if (i == 1) { ans[prime[j]] = prime[j] % mod; cnt[prime[j]] = f(prime[j]); continue; } cnt[i * prime[j]] = cnt[i] + cnt[prime[j]]; if (i < prime[j]) { ans[i * prime[j]] = (ans[i] * p10[cnt[prime[j]]] % mod + ans[prime[j]] % mod) % mod; } else ans[i * prime[j]] = (ans[prime[j]] * p10[cnt[i]] % mod + ans[i] % mod) % mod; } } for (int i = 2; i <= n; i++) { sum = (sum + ans[i]) % mod; } cout << sum << endl; return 0; }
|