题目描述
算数基本定理,又称唯一分解定理,算术基本定理可表述为:任何一个大于1的自然数 N,如果N不为质数,那么N可以唯一分解成有限个质数的乘积。即N=p1e1⋅p2e2…pmem(p1<p2<…pm)N=p_1^{e_1}\cdot p_2{e_2}…p_m{e_m}(p_1 < p_2< … p_m)N=p1e1⋅p2e2…pmem(p1<p2<…pm)
朴素的质因子分解算法就是利用了算数基本定理,依次枚举p判断N是否包含素因子p。
牛牛最近对于质因数分解产生了浓厚的兴趣。
牛牛定义了一个函数F(x),它表示将x做质因数分解后得到的数字从小到大升序排列,然后将其“拼接”成一个大整数。
例如1500=22355*5,F(1500)=223555。
牛牛现在想要知道∑i=2nF(i)\sum_{i=2}^{n}F(i)∑i=2nF(i)的值。
由于这个结果非常大,所以你只用告诉牛牛最终答案对109+710^9+7109+7取余数的结果即可。
输入描述:
仅一行一个正整数n(2≤n≤4×106)n(2 \leq n \leq 4 \times 10^6)n(2≤n≤4×106)
输出描述:
仅一行,表示答案对109+710^9+7109+7取余数的结果。
示例1
输入
3
输出
5
说明
示例2
输入
10
输出
342
说明
F(2)=2
F(3)=3
F(4)=22
F(5)=5
F(6)=23
F(7)=7
F(8)=222
F(9)=33
F(10)=25
2+3+22+5+23+7+222+33+25=342
思路
很容易发现,因为遵循唯一分解性定理, 所以每个数都只有唯一的分解方式, 但看数据范围如果暴力肯定会超时, 我们发现对于一个分解方式 2 x 2 x 3 x3 , 只需在这个分解方式后面新增一个比3大的素数就可以拼成另外一个数了, 我们倘如能利用前面的分解来合成新的的数就可以了, 有两种思路 一种dp, 在筛的时候就记录答案, 另外一种是dfs来合成数。 但两种都有一个注意点, n <= 4e6 显然 2^22小于 4e6 所以long long 都不能存下,
知识点 如果 x % mod = y;
设 z * 10 + w = x, 则 (z * 10 % mod + w % mod) % mod = y;
详细见于代码
1.筛法————线性筛
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <string>
#define ull long long
using namespace std;
const int N=4e6+20,MOD=1e9+7;
int prime[N],lowprime[N];
string f[N];
bool vis[N];
int n;
ull ans=0;
ull to_ll(string ans1){
ull tmp=0;
for(int i = 0; i < ans1.size(); i++)
tmp = tmp * 10 + ans1[i] - '0';
return tmp;
}
void init(){
vis[1]=true;
for(int i=2;i<= n;i++){
if(!vis[i]){
prime[++prime[0]]=i;
f[i] = to_string(i);
}
else{
int mmod=lowprime[i];
f[i] = to_string(mmod) + f[i/mmod];
}
for(int j=1;i*prime[j]< N;j++){
vis[i*prime[j]]=true;
lowprime[i*prime[j]]=prime[j];
if(i%prime[j]==0) break;
}
if(i==n)
return ;
}
}
int ans2[30];
int main(){
cin>>n;
init();
for(int i = 2; i <= n; i++)
{
reverse(f[i].begin(), f[i].end());
for(int j = 0; j < f[i].size(); j++)
{
ans2[j] += (f[i][j] - '0');
}
}
//for(int i = 0; i < 29; i ++) cout << ans2[i] << " ";
long long ans1 = 0;
int maxx = 0;
for(int i = 0; i < 29; i++)
{
ans2[i + 1] = ans2[i + 1] + ans2[i] / 10;
ans2[i] %= 10;
if(ans2[i] != 0) maxx = i;
}
for(int i = maxx; i >= 0; i--)
{
ans1 = (ans1 * 10 + ans2[i]) % MOD;
}
cout << ans1 << endl;
return 0;
}
- dfs
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 4e6 + 10;
ll mod = 1e9 + 7;
ll sum;
ll n;
int p[N], cnt, vis[N];
void get_p()
{
vis[1] = 1;
for(int i = 2; i <= N; i++)
{
if(vis[i] == 0)
{
p[++cnt] = i;
}
for(int j = 1; p[j] * i < N; j ++)
{
vis[p[j] * i] = 1;
if(i % p[j] == 0) break;
}
}
}
ll cal(string s)
{
ll t = 0;
for(int i = 0; i < s.size(); i++)
{
t = (t * 10 + s[i] - '0') % mod;
}
return t;
}
void dfs(int x, string s, ll tmp)
{
if(s != "")
sum = (sum + cal(s)) % mod;
for(int i = x; i <= cnt && p[i] * tmp <= n; i ++)
{
dfs(i, s + to_string(p[i]), tmp * p[i]);
}
}
int main()
{
get_p();
cin >> n;
dfs(1, "", 1);
cout << sum << endl;
return 0;
}