在复杂度 O ( n 3 4 / l o g n ) O(n^{\frac{3}{4}}/logn) O(n43/logn)下解决一些积性函数的和
做一些规定:
p r i m e ( i ) : i 为 质 数 时 , 为 一 , 否 则 为 0 prime(i):i为质数时,为一,否则为0 prime(i):i为质数时,为一,否则为0
p k : p_k: pk:表示第 k k k个质数,规定第零个质数为1;
m i n p ( i ) : 表 示 i 的 最 小 质 因 子 minp(i):表示i的最小质因子 minp(i):表示i的最小质因子
g ( n , j ) = ∑ i = 1 n [ p r i m e ( i ) o r ( m i n p ( i ) > p j ) ] f [ i ] g(n,j)=\sum\limits_{i=1}^{n}[prime(i)or(minp(i)>p_j)]f[i] g(n,j)=i=1∑n[prime(i)or(minp(i)>pj)]f[i]
S ( n , j ) = ∑ i = 1 n [ m i n p ( i ) > = p j ] f [ i ] S(n,j)=\sum\limits_{i=1}^{n}[minp(i)>=p_j]f[i] S(n,j)=i=1∑n[minp(i)>=pj]f[i]
p p p都是指质数
目的:求 ∑ i = 1 n f ( i ) \sum\limits_{i=1}^nf(i) i=1∑nf(i)
要求:
f ( i ) f(i) f(i)是一个积性函数(即, a , b a,b a,b互质时, f ( a b ) = f ( a ) f ( b ) f(ab)=f(a)f(b) f(ab)=f(a)f(b))
f ( p k ) f(p^k) f(pk)可以快速求
f ( p ) f(p) f(p)是一个是一个关于 p p p的项数较少的多项式,或可以快速求值
令 f ( p ) = c 1 p k 1 + c 2 p k 2 + ⋯ f(p)=c_1p^{k_1}+c_2p^{k_2}+\cdots f(p)=c1pk1+c2pk2+⋯
因为只要分别求出 p k p^k pk的前 n n n项和,再与系数相乘,再把各项加起来就行
所以令 f ( p ) f(p) f(p)= p k p^k pk
我们把问题简化为两部分来
求解 ∑ i = 1 n [ p r i m e ( i ) ] f ( i ) \sum\limits_{i=1}^{n}[prime(i)]f(i) i=1∑n[prime(i)]f(i)
因为一个合数 a a a的最小质因子不大于 a \sqrt{a} a
所以 ∑ i = 1 n [ p r i m e ( i ) ] f ( i ) = g ( n , ∣ p ∣ ) \sum\limits_{i=1}^{n}[prime(i)]f(i)=g(n,|p|) i=1∑n[prime(i)]f(i)=g(n,∣p∣),这里的|p|表示不大于 n n n的最大质数。
显然 g ( n , 0 ) = ∑ i = 2 n f ( i ) g(n,0)=\sum\limits_{i=2}^{n}f(i) g(n,0)=i=2∑nf(i)
这一部分怎么办,我们最终要得到的是 ∑ i = 1 n [ p r i m e ( i ) ] f ( i ) \sum\limits_{i=1}^{n}[prime(i)]f(i) i=1∑n[prime(i)]f(i)所以我们在一部分假设对于任意 i i i,都有 f ( i ) = i k f(i)=i^k f(i)=ik,最后得到的是质数的 f f f值,所以并不会影响结果
现在来考虑怎么 g ( n , j − 1 ) 转 移 到 g ( n , j ) g(n,j-1)转移到g(n,j) g(n,j−1)转移到g(n,j)。
从 g ( n , j − 1 ) 转 到 g ( n , j ) g(n,j-1)转到g(n,j) g(n,j−1)转到g(n,j)会少掉一些合数的最小质因子是 p j p_j pj的,所以要减掉。
若 p j ⋅ p j > n p_j\cdot p_j>n pj⋅pj>n则不存在这样的合数
此时有 g ( n , j ) = g ( n , j − 1 ) g(n,j)=g(n,j-1) g(n,j)=g(n,j−1)
那么 p j ⋅ p j < = n p_j\cdot p_j<=n pj⋅pj<=n时 p j < n p j p_j<\frac{n}{p_j} pj<pjn
所以 g ( n p j , j − 1 ) g(\frac{n}{p_j},j-1) g(pjn,j−1)包含了小于 p j p_j pj的质数和大于 p j p_j pj且其最小质因子大于等于 p j p_j pj的 f f f值
所以 g ( n p j , j − 1 ) − g ( p j , j − 1 ) g(\frac{n}{p_j},j-1)-g(p_j,j-1) g(pjn,j−1)−g(pj,j−1)包含了最小质因子大于等于 p j p_j pj的 f f f值。
所以有 g ( n , j ) = g ( n , j − 1 ) − f ( p j ) ( g ( n p j − g ( p j , j − 1 ) g(n,j)=g(n,j-1)-f(p_j)(g(\frac{n}{p_j}-g(p_j,j-1) g(n,j)=g(n,j−1)−f(pj)(g(pjn−g(pj,j−1)
求解 S ( n , 1 ) S(n,1) S(n,1) 则答案为 S ( n , 1 ) + f ( 1 ) S(n,1)+f(1) S(n,1)+f(1)
易知 S ( n , m ) = 0 S(n,m)=0 S(n,m)=0, p m p_m pm为大于 n n n的质数
第二部分其实道理跟第一部分一样的,自己推导一下就行。
结果:
S ( n , j ) = g ( n , ∣ p ∣ ) − ∑ i = 1 j − 1 + ∑ k = j p k 2 < = n ∑ e = 1 p k e + 1 < = n S ( n p k e , k + 1 ) f ( p k ) + f ( p k + 1 ) S(n,j)=g(n,|p|)-\sum\limits_{i=1}^{j-1}+\sum\limits_{k=j}^{p_k^2<=n}\sum\limits_{e=1}^{p_k^{e+1}<=n}S(\frac{n}{p_k^e},k+1)f(p_k)+f(p_{k+1}) S(n,j)=g(n,∣p∣)−i=1∑j−1+k=j∑pk2<=ne=1∑pke+1<=nS(pken,k+1)f(pk)+f(pk+1)
可以看到我们需要的 g g g点有 n , n / 2 , n / 3 ⋯ 1 n,n/2,n/3\cdots 1 n,n/2,n/3⋯1一共 n \sqrt{n} n个点,所以需要一些分块
例题:简单的函数
#include
#define ll long long
#define ull unsiged ll
#define rep(i, l, r) for (int i = l; i <= r; i++)
#define per(i, r, l) for (int i = r; i >= l; i--)
#define boots ios::sync_with_stdio(0); cin.tie(0)
#define endl '\n'
#define mod 1000000007
#define inf 0x3f3f3f3f
#define lnf LLONG_MAX
#define si(n) scanf("%d", &n)
#define sl(n) scanf("%lld", &n)
#define pf(n) printf("%lld\n", n)
#define sz size
using namespace std;
//const db pi = 3.1415926535898;
const int N = 2e5 + 10;
const int INV2 = 500000004;
int top;
unordered_map<ll, ll> mp;
int pri[N], ji[N];
ll g[N], h[N], pris[N];
ll w[N];
//pri[i]表示第几个质数,pris[i]表示前i个质数的和
void init(ll MX) {
memset(ji, 0, sizeof(ji));
pris[0] = 0;
top = 0;
for (int i = 2; i <= MX; i++) {
if (!ji[i]) {
pri[++top] = i;
pris[top] = (pris[top - 1] + i) % mod;
}
for (int j = 1; j <= top && 1ll * i * pri[j] <= MX; j++) {
int cur = i * pri[j];
ji[cur] = 1;
if (i % pri[j] == 0)
break;
}
}
}
void add(ll &a, ll b) {
a = (a + b) % mod;
if (a < 0)
a += mod;
return;
}
ll S(ll n, ll m) {
if (n <= 1 || pri[m] > n)
return 0;
ll kt = mp[n];
ll res = (g[kt] - h[kt] - (pris[m - 1] - m + 1)) % mod;
if (res < 0)
res += mod;
if (m == 1)
res += 2;
for (int k = m; k <= top && 1ll * pri[k] * pri[k] <= n; k++) {
ll ans = pri[k];
for (int i = 1; ans * pri[k] <= n; i++, ans *= pri[k]) {
add(res, (1ll * (S(n / ans, k + 1)) * (pri[k] ^ i) % mod + (pri[k] ^ (i + 1))) % mod);
}
}
return res;
}
int main() {
ll n;
while (cin >> n) {
ll fb = sqrt(n);
init(fb);
ll j;
int times = 0;
ll ans;
for (ll i = 1; i <= n; i = j + 1) {
w[++times] = n / i;
j = n / (n / i);
h[times] = (w[times] - 1) % mod;
g[times] = (((w[times] % mod * (w[times] + 1) % mod) % mod * INV2) % mod - 1 + mod) % mod;
mp[w[times]] = times;
}
for (int i = 1; i <= top; i++) {
ll k = 1ll * pri[i] * pri[i];
for (int j = 1; j <= times && k <= w[j]; j++) {
int kt = mp[w[j] / pri[i]];
add(g[j], mod - 1ll * pri[i] * (g[kt] - pris[i - 1]) % mod);
add(h[j], mod - (h[kt] - i + 1) % mod);
}
}
//g[i]-h[i]=w[i]以内
//w[i]表示n/i,mp[n/i]=i,h[i]表示n/i(含)内有多少个质数,g[i]=n/i内的质数之和表示
cout << (S(n, 1) + 1) % mod << endl;
}
}