链接: link.
思路:在欧拉筛的过程中开个数组处理每个数分解质因数后的连接起来的值,巧妙运用欧拉筛。
欧拉筛链接: link.
代码
#include <bits/stdc++.h>
#define ll long long
#define T int T;scanf("%d", &T);while(T--)
using namespace std;
const int mod = 1e9+7;
const int maxn = 4e6+10;
ll prim[maxn]; //记录第i个素数
ll len[maxn]; //记录每个数的位数
ll p[maxn]; //记录每个数分解质因数的后连接起来的值
ll vis[maxn]; //标记素数
ll cnt; //素数个数
ll ans = 0;
ll n;
void oula(){
cnt = 1;
for(int i = 2; i <= n; i ++){
if(vis[i]==0){ //没被标记过,素数
prim[cnt++] = i;
p[i] = i; //素数的值就是自己本身
ll x = i;
len[i] = 1; //求出素数长度,便于下面连接
while(x){
len[i]*=10;
x/=10;
}
}
for(int j = 1; j < cnt && prim[j]*i <= n; j ++){
vis[i*prim[j]] = 1; //把合数标记掉
p[i*prim[j]] = (len[i]*prim[j]+p[i])%mod; //核心
len[prim[j]*i] = len[prim[j]]*len[i]%mod; //核心
if(i%prim[j]==0){ //保证每个合数只会被他的最小之质因子筛去
break; //经典欧拉筛的核心语句,这样能保证每个数只会被自己最小的因子筛掉一次
}
}
ans = (ans+p[i])%mod;
}
}
int main(){
cin >> n;
oula();
cout << ans << endl;
return 0;
}