题意
求
∑ i = 1 m μ ( i n ) \sum_{i=1}^{m} \mu(in) i=1∑mμ(in)
m ≤ 2 × 1 0 9 , n ≤ 1 0 12 m \le 2×10^9,n\le 10^{12} m≤2×109,n≤1012
分析:
首先分析 n n n 的因子中有没有平方,如果有那么答案就是 0 0 0
如果 n n n 的因子没有平方,设某个因子为 p p p,原式就可以拆成
∑ i = 1 m μ ( i ⋅ n p ⋅ p ) \sum_{i=1} ^{m}\mu(i\cdot\frac{n}{p}\cdot p) i=1∑mμ(i⋅pn⋅p)
莫比乌斯函数是积性函数,考虑把 p p p 分出去,那么 p p p 与 n p \dfrac{n}{p} pn 一定是互质的,但 i ⋅ n p i\cdot \dfrac{n}{p} i⋅pn 并不一定互质,那么就考虑 i i i 与 p p p 的关系,在 [ 1 , m ] [1,m] [1,m] 中只有 p p p 的倍数才与 p p p 不互质,所以要加上这一部分。
∑ i = 1 m μ ( i ⋅ n p ) μ ( p ) + ∑ i = 1 ⌊ m p ⌋ μ ( i ⋅ p ⋅ n p ) \sum_{i=1}^{m}\mu(i\cdot\frac{n}{p})\mu(p)+\sum_{i=1}^{\lfloor \frac{m}{p} \rfloor}\mu(i\cdot p \cdot \frac{n}{p}) i=1∑mμ(i⋅pn)μ(p)+i=1∑⌊pm⌋μ(i⋅p⋅pn)
由于 p p p 是单因子,所以 μ ( p ) = − 1 \mu(p)=-1 μ(p)=−1
∑ i = 1 ⌊ m p ⌋ μ ( i n ) − ∑ i = 1 m μ ( i ⋅ n p ) \sum_{i=1}^{\lfloor \frac{m}{p} \rfloor}\mu(i n) - \sum_{i=1}^{m}\mu(i\cdot\frac{n}{p}) i=1∑⌊pm⌋μ(in)−i=1∑mμ(i⋅pn)
设 S ( n , m ) = ∑ i = 1 m μ ( i n ) S(n,m)=\sum\limits_{i=1}^{m}\mu(in) S(n,m)=i=1∑mμ(in),那么得到递推式
S ( n , m ) = S ( n , m p ) − S ( n p , m ) S(n,m)=S(n,\frac{m}{p})-S(\frac{n}{p},m) S(n,m)=S(n,pm)−S(pn,m)
那么就可以每次枚举 n n n 的质因子 p p p,递归求解,那么递归边界就是 S ( 0 , n ) S(0,n) S(0,n) 和 S ( 1 , m ) S(1,m) S(1,m),也就是莫比乌斯函数前缀和,用杜教筛处理一下就好了
代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e6 + 5;
int t, n, m, mobius[N], primes[N], cnt, sum[N];
bool st[N];
unordered_map<int, int> mp;
void get_mobius(int n) {
mobius[1] = 1;
for (int i = 2; i <= n; i ++) {
if (!st[i]) {
primes[cnt ++] = i;
mobius[i] = -1;
}
for (int j = 0; primes[j] * i <= n; j ++) {
int t = primes[j] * i;
st[t] = 1;
if (i % primes[j] == 0) {
mobius[t] = 0;
break;
}
mobius[t] = -mobius[i];
}
}
for (int i = 1; i <= n; i ++) sum[i] = sum[i - 1] + mobius[i];
}
int Sum(int n) {
if (n < N) return sum[n];
if (mp[n]) return mp[n];
int res = 1;
for (int l = 2, r; l <= n; l = r + 1) {
r = n / (n / l);
res -= Sum(n / l) * (r - l + 1);
}
return mp[n] = res;
}
int S(int n, int m) {
if (m == 0) return 0;
if (n == 1) return Sum(m);
int flag = 0;
for (int i = 2; i * i <= n; i ++) {
if (n % i == 0) {
flag = 1;
return S(n, m / i) - S(n / i, m);
}
}
if (!flag) return S(n, m / n) - S(1, m);
}
signed main() {
get_mobius(N - 1);
cin >> m >> n;
t = n;
for (int i = 2; i * i <= t; i ++) {
if (t % i == 0) {
int cnt = 0;
while (t % i == 0) {
t /= i;
cnt ++;
if (cnt == 2) {
cout << 0 << endl;
return 0;
}
}
}
}
cout << S(n, m) << endl;
}