设 f ( n ) = ∑ d ∣ n ∣ μ ( d ) ∣ \displaystyle f(n)=\sum_{d\mid n}|\mu(d)| f(n)=d∣n∑∣μ(d)∣
求 ∑ i = 1 m f ( n i ) m o d 1 0 9 + 7 \displaystyle\sum_{i=1}^mf(ni)\mod 10^9+7 i=1∑mf(ni)mod109+7
1 ≤ n , m ≤ 1 0 7 1\le n,m\le10^7 1≤n,m≤107
设 w ( n ) w(n) w(n)表示 n n n的质因子个数,根据 μ \mu μ的定义,有
f ( n ) = ∑ k = 0 w ( n ) ( w ( n ) k ) ∣ ( − 1 ) k ∣ = 2 w ( n ) \displaystyle f(n)=\sum_{k=0}^{w(n)}{w(n)\choose k}|(-1)^k|=2^{w(n)} f(n)=k=0∑w(n)(kw(n))∣(−1)k∣=2w(n)
显然 f ( n ) f(n) f(n)是一个积性函数,且满足 f ( a b ) = f ( a ) f ( b ) f ( gcd ( a , b ) ) \displaystyle f(ab)=\frac{f(a)f(b)}{f(\gcd(a,b))} f(ab)=f(gcd(a,b))f(a)f(b)。
化简原式:
∑ i = 1 m f ( i n ) = f ( n ) ∑ i = 1 m f ( i ) f ( gcd ( n , i ) ) = f ( n ) ∑ d ∣ n 1 f ( d ) ∑ i = 1 m f ( i ) [ gcd ( i , n ) = d ] = f ( n ) ∑ d ∣ n 1 f ( d ) ∑ i = 1 ⌊ m d ⌋ f ( i d ) [ gcd ( i , n d ) = 1 ] = f ( n ) ∑ d ∣ n 1 f ( d ) ∑ i = 1 ⌊ m d ⌋ f ( i d ) ∑ p ∣ i , p ∣ n d μ ( p ) = f ( n ) ∑ d ∣ n ∑ p d ∣ n μ ( p ) f ( d ) ∑ i = 1 ⌊ m p d ⌋ f ( i p d ) = f ( n ) ∑ T ∣ n ∑ d ∣ T μ ( T d ) f ( d ) ∑ i = 1 ⌊ m T ⌋ f ( i T ) = f ( n ) ∑ T ∣ n g ( T ) ∑ i = 1 ⌊ m T ⌋ f ( i T ) \begin{aligned} \sum_{i=1}^mf(in)=&f(n)\sum_{i=1}^m\frac{f(i)}{f(\gcd(n,i))}\\ &=f(n)\sum_{d\mid n}\frac1{f(d)}\sum_{i=1}^mf(i)[\gcd(i,n)=d]\\ &=f(n)\sum_{d\mid n}\frac1{f(d)}\sum_{i=1}^{\lfloor\frac md\rfloor}f(id)[\gcd(i,\frac nd)=1]\\ &=f(n)\sum_{d\mid n}\frac1{f(d)}\sum_{i=1}^{\lfloor\frac md\rfloor}f(id)\sum_{p|i,p|\frac nd}\mu(p)\\ &=f(n)\sum_{d\mid n}\sum_{pd\mid n}\frac{\mu(p)}{f(d)}\sum_{i=1}^{\lfloor\frac m{pd}\rfloor}f(ipd)\\ &=f(n)\sum_{T\mid n}\sum_{d\mid T}\frac{\mu(\frac Td)}{f(d)}\sum_{i=1}^{\lfloor\frac mT\rfloor}f(iT)\\ &=f(n)\sum_{T\mid n}g(T)\sum_{i=1}^{\lfloor\frac mT\rfloor}f(iT) \end{aligned} i=1∑mf(in)=f(n)i=1∑mf(gcd(n,i))f(i)=f(n)d∣n∑f(d)1i=1∑mf(i)[gcd(i,n)=d]=f(n)d∣n∑f(d)1i=1∑⌊dm⌋f(id)[gcd(i,dn)=1]=f(n)d∣n∑f(d)1i=1∑⌊dm⌋f(id)p∣i,p∣dn∑μ(p)=f(n)d∣n∑pd∣n∑f(d)μ(p)i=1∑⌊pdm⌋f(ipd)=f(n)T∣n∑d∣T∑f(d)μ(dT)i=1∑⌊Tm⌋f(iT)=f(n)T∣n∑g(T)i=1∑⌊Tm⌋f(iT)
其中 g ( T ) = ∑ d ∣ T μ ( T d ) f ( d ) \displaystyle g(T)=\sum_{d\mid T}\frac{\mu(\frac Td)}{f(d)} g(T)=d∣T∑f(d)μ(dT),即 g = 1 f × μ \displaystyle g=\frac1f\times \mu g=f1×μ,也是一个积性函数,用线性筛的方法推导可得:
g ( T ) = { ( − 1 2 ) w ( T ) , T = ∏ i = 1 w ( T ) p i 0 , o t h e r w i s e g(T)=\left\{\begin{aligned} \Big(-\frac12\Big)^{w(T)},&&T=\prod_{i=1}^{w(T)} p_i\\ 0,&&{\rm otherwise} \end{aligned}\right. g(T)=⎩⎪⎪⎨⎪⎪⎧(−21)w(T),0,T=i=1∏w(T)piotherwise
也就是说对于 T ∣ n T\mid n T∣n的 g ( T ) g(T) g(T),只有当 T T T是 n n n的质因子集合的某个子集中所有元素的乘积时,才会产生贡献。而 n ≤ 1 0 7 n\le10^7 n≤107时, w ( n ) ≤ 8 w(n)\le8 w(n)≤8,故可以在 O ( 8 ⋅ 2 8 ) O(8\cdot2^8) O(8⋅28)的时间内枚举出所有有贡献的 T T T,这样比直接枚举约数要快一些。
由于内存限制, ∑ i = 1 ⌊ m T ⌋ f ( i T ) \displaystyle \sum_{i=1}^{\lfloor\frac mT\rfloor}f(iT) i=1∑⌊Tm⌋f(iT)不能预处理。
考虑离线,把所有 ∑ i = 1 ⌊ m T ⌋ f ( i T ) \displaystyle \sum_{i=1}^{\lfloor\frac mT\rfloor}f(iT) i=1∑⌊Tm⌋f(iT)的询问,按 T T T为第一关键字, ⌊ m T ⌋ \lfloor\frac mT\rfloor ⌊Tm⌋为第二关键字排序然后暴力计算即可。
计算答案时注意要乘上 f ( n ) g ( T ) f(n)g(T) f(n)g(T)的系数。
时间复杂度 O ( n log n + T ( n + 8 ⋅ 2 8 ) ) O(n\log n+T(\sqrt n+8\cdot 2^8)) O(nlogn+T(n+8⋅28))
#include
using namespace std;
const int N = 1e7 + 5, P = 1e9 + 7, Inv2 = (P + 1) / 2;
typedef long long ll;
struct Data {
int d, m, w, id;
};
int n, m, q, Ans[10005];
int is[N], prime[N], f[N], g[N];
vector<Data> Q;
int main() {
n = 1e7;
f[1] = g[1] = 1;
for (int i = 2; i <= n; ++i) {
if (!is[i])
prime[++prime[0]] = i, f[i] = 2, g[i] = P - Inv2;
for (int j = 1, x; j <= prime[0] && (x = i * prime[j]) <= n; ++j) {
is[x] = 1;
if (i % prime[j])
f[x] = 2 * f[i] % P, g[x] = (ll)g[prime[j]] * g[i] % P;
else {
f[x] = f[i];
break;
}
}
}
scanf("%d", &q);
for (int T = 1; T <= q; ++T) {
scanf("%d%d", &n, &m);
int t = n;
vector<int> div;
for (int d = 2; d * d <= t; ++d)
if (t % d == 0) {
div.push_back(d);
while (t % d == 0)
t /= d;
}
if (t != 1)
div.push_back(t);
for (int s = 0; s < (1 << div.size()); ++s) {
int d = 1;
for (int i = 0; i <= (int)div.size() - 1; ++i)
if (s & (1 << i))
d *= div[i];
if (m < d || !g[d])
continue;
Q.push_back({d, (m / d) * d, int((ll)f[n] * g[d] % P), T});
}
}
sort(Q.begin(), Q.end(),
[](Data a, Data b) { return a.d == b.d ? a.m < b.m : a.d < b.d; });
ll w;
int d = 0, i;
for (auto t : Q) {
if (t.d != d)
d = i = t.d, w = 0;
for (; i <= t.m; i += d)
w += f[i];
Ans[t.id] = (Ans[t.id] + (ll)t.w * (w %= P) % P) % P;
}
for (int i = 1; i <= q; ++i)
printf("%d\n", Ans[i]);
return 0;
}