Address
Luogu #5325
Solution
- 記 pi 表示第 i 小的質數(p[0]=1),s1[x]=∑i=1xp[x],s2[x]=∑i=1xp[x]2。
- 記 g1(x,i) 爲:j=1∑x[j是質數或j的最小質因子大於pi]j
- 記 g2(x,i) 爲:j=1∑x[j是質數或j的最小質因子大於pi]j2
- 因爲 n 以內的合數的最小質因子爲 O(n),所以第二維的 i 滿足:pi2≤n。
- 記 s(x,y) 爲:j=1∑x[j的最小質因子大於py]j2−j
- 那麼顯然有: ans=S(x,y)+1
- 假設我們已經求得了所有的 g1(x,i),g2(x,i)。
- 考慮如何求 s(x,y):
- 我們分別考慮質數與合數對答案的貢獻。
- 對於質數,記 n 以內的質數個數爲 c,我們要求的就是:res=j=y+1∑cpj2−pj
- 我們把它轉換爲兩個前綴和相減的形式(前 c 個的貢獻 − 前 j 個的貢獻),並且利用上 g1,g2,那麼有:res=g2(x,c)−g1(x,c)−(s2[y]−s1[y])
- 對於合數,有最小質因子大於 py 的限制。
- 我們枚舉 i,j,並計算所有滿足以下條件的合數 a 對答案的貢獻:
1.a 的最小質因子爲 pi。
2.a 可以分解出 j 個 pi。
- 我們把每個合法的 a 都分解出因數 pij,記 b 爲分解後的 a,那麼 b 要滿足條件:
1.b 的最小質因子大於 pi 或 b=1。
2.b≤⌊pijx⌋。
- 那麼我們就得出了遞推式:s(x,y)=res−i=y+1∑cj=1,pij≤x∑f(pij)∗(s(⌊pijx⌋,i)+[j=1])
- 現在還有一個問題,就是求 g1,g2。
- 我們可以這樣求 g1(g2 同理):
- 先讓 g1(x,i)=g1(x,i−1),接着要減去所有滿足最小質因子等於 pi的合數的貢獻。
- 我們還是把這些合數分解出因數 pi,然後分解後的數 d 要滿足以下條件:
1.d 的最小質因子大於 pi−1。
2.d≤⌊pix⌋。
- 顯然有:g1(x,i)=g1(x,i−1)−pi(g1(⌊pix⌋,i−1)−s1[i−1])
- 然後還有一個問題就是 g1,g2,s 的第一維可能到 O(n) 級別,需要離散化。
- 顯然第一維只可能是某個 ⌊in⌋ 的值。
- 那麼當 x≤n時,記 id1[x] 表示 x 離散化後的值。
- 否則,記 id2[n/x] 表示 x 離散化後的值。
Code
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int e = 1e6 + 5, mod = 1e9 + 7;
ll g1[e], g2[e], n, s1[e], s2[e], a[e];
bool bo[e];
int cnt, p[e], tot, id1[e], id2[e], s, inv6;
inline int plu(int x, int y)
{
(x += y) >= mod && (x -= mod);
return x;
}
inline int sub(int x, int y)
{
(x -= y) < 0 && (x += mod);
return x;
}
inline int ksm(int x, int y)
{
int res = 1;
while (y)
{
if (y & 1) res = (ll)res * x % mod;
y >>= 1;
x = (ll)x * x % mod;
}
return res;
}
inline int calc1(ll x)
{
x %= mod;
return (ll)x * (x + 1) / 2 % mod;
}
inline int calc2(ll x)
{
x %= mod;
return (ll)x * (x + 1) % mod * (2 * x + 1) % mod * inv6 % mod;
}
inline void init()
{
inv6 = ksm(6, mod - 2); s = sqrt(n);
ll i, j;
for (i = 1; i <= n; i = j + 1)
{
a[++tot] = n / i;
j = n / a[tot];
g1[tot] = sub(calc1(a[tot]), 1);
g2[tot] = sub(calc2(a[tot]), 1);
if (a[tot] <= s) id1[a[tot]] = tot;
else id2[n / a[tot]] = tot;
}
}
inline void sieve()
{
int i, j;
for (i = 2; i <= s; i++)
{
if (!bo[i])
{
p[++cnt] = i;
s1[cnt] = plu(s1[cnt - 1], i);
s2[cnt] = plu(s2[cnt - 1], (ll)i * i % mod);
}
for (j = 1; j <= cnt && i * p[j] <= s; j++)
{
bo[i * p[j]] = 1;
if (i % p[j] == 0) break;
}
}
}
inline void solve_g()
{
int i, j;
for (i = 1; i <= cnt; i++)
{
for (j = 1; j <= tot; j++)
if ((ll)p[i] * p[i] <= a[j])
{
ll x = a[j], y = x / p[i];
int k = y <= s ? id1[y] : id2[n / y], z = x <= s ? id1[x] : id2[n / x];
g1[z] = sub(g1[z], (ll)p[i] * sub(g1[k], s1[i - 1]) % mod);
g2[z] = sub(g2[z], (ll)p[i] * p[i] % mod * sub(g2[k], s2[i - 1]) % mod);
}
}
}
inline int dfs(ll x, int y)
{
if (p[y] >= x) return 0;
int i, j, k = x <= s ? id1[x] : id2[n / x];
int res = sub(sub(g2[k], g1[k]), sub(s2[y], s1[y]));
ll pj;
for (i = y + 1; i <= cnt && (ll)p[i] * p[i] <= x; i++)
for (j = 1, pj = p[i]; pj <= x; j++, pj = pj * p[i])
{
int f = pj % mod;
f = (ll)f * sub(f, 1) % mod;
res = plu(res, (ll)f * plu(dfs(x / pj, i), j != 1) % mod);
}
return res;
}
int main()
{
cin >> n; init(); sieve(); solve_g();
cout << plu(dfs(n, 0), 1) << endl;
return 0;
}