前言
昨天是用分段打表过的,看了题解发现可以利用埃氏筛法,感觉还是有一定思维量的。
题目链接
题解
在埃氏筛法中,每个合数都有一个质数以及他的倍数筛出,也就是
v
i
s
[
i
∗
j
]
=
1
vis[i*j]=1
vis[i∗j]=1,其中
i
i
i是质数,
i
×
j
i\times j
i×j自然是
i
i
i的倍数。并且这里的
i
i
i是从小到大枚举的,刚好符合题意。
当枚举到质因子
i
i
i时,若
j
j
j中还包含
k
k
k个质因子
i
i
i,那我们总共需要将
k
+
1
k+1
k+1个
i
i
i连接起来,也就是
d
p
[
i
×
j
]
=
d
p
[
i
×
j
]
×
10
+
i
dp[i\times j]=dp[i\times j]\times 10+i
dp[i×j]=dp[i×j]×10+i,需要注意的是,这里的
×
10
\times 10
×10是针对个位数的质因子而言。比如
11
11
11这种不止一位数的因子,我们需要
×
100
\times 100
×100。
代码
/*
* @Author: hesorchen
* @Date: 2020-11-26 09:12:46
* @LastEditTime: 2021-02-04 11:09:41
* @Description: 栽种绝处的花
*/
#include <bits/stdc++.h>
using namespace std;
const long long mod = 1000000007;
bool vis[4000010];
long long dp[4000010];
long long get(long long x)
{
long long res = 1;
while (x)
{
x /= 10;
res *= 10;
}
return res;
}
void pre()
{
for (long long i = 2; i <= 4e6; i++)
{
if (!vis[i])
{
dp[i] = i;
long long len = get(i); //不同位数需要乘不同数量的10
for (long long j = 2; i * j <= 4e6; j++)
{
vis[i * j] = 1;
dp[i * j] = dp[i * j] * len % mod + i % mod; //连上一个i
if (j % i == 0)
{
long long cnt = 0, jj = j;
while (jj % i == 0) //j里边包含cnt个i,都需要连上
jj /= i, cnt++;
for (long long k = 1; k <= cnt; k++)
dp[i * j] = (dp[i * j] * len % mod + i) % mod;
}
}
}
}
}
int main()
{
long long n;
cin >> n;
pre();
long long out = 0;
for (long long i = 2; i <= n; i++)
out = (out + dp[i]) % mod;
cout << out << endl;
return 0;
}