給一個長度爲 \(n\) 的數組 \(a[1\dots n]\) ,知足 \(\sum_{m|x}a[x] = \mu(m)\),求 \(a[m]\)。c++
\(n\le 10^{18}, m\le 10^9, \frac{n}{m}\le10^9,n\geq m\)git
由另外一種形式的莫比烏斯反演:數組
\[ \begin{aligned} a[m] &= \sum_{m|x}\mu(\frac{x}{m})\mu(x)\\ &=\sum_{i=1}^{\frac{n}{m}}\mu(i)\mu(im)\\ &=\mu(m)\sum_{i=1}^{\lfloor\frac{n}{m}\rfloor}\mu(i)^2[\gcd(i, m) = 1]\\ \end{aligned} \]spa
後面那個 \(\sum\) 就是在求 \(1\dots \frac{n}{m}\) 中與 \(m\) 互質且不能寫成徹底平方數的倍數的個數。code
相似於 [中山市選2011]徹底平方數,能夠容斥求:blog
令 \(N = \lfloor\frac{n}{m}\rfloor\),ip
\[ \begin{aligned} a[m] &=\mu(m)\sum_{i=1}^{\frac{n}{m}}\mu(i)^2[\gcd(i, m) = 1]\\ &=\mu(m)\sum_{i=1}^{\sqrt{N}}\mu(i)\sum_{j=1}^{\lfloor\frac{N}{i^2}\rfloor}[\gcd(i^2j,m)=1]\\ &=\mu(m)\sum_{i=1}^{\sqrt{N}}\mu(i)[\gcd(i,m)=1]\sum_{j=1}^{\lfloor\frac{N}{i^2}\rfloor}[\gcd(j,m)=1]\\ &=\mu(m)\sum_{i=1}^{\sqrt{N}}\mu(i)[\gcd(i,m)=1]\sum_{j=1}^{\lfloor\frac{N}{i^2}\rfloor}\sum_{d|\gcd(j,m)}\mu(d)\\ &=\mu(m)\sum_{i=1}^{\sqrt{N}}\mu(i)[\gcd(i,m)=1]\sum_{d|m}\mu(d)\lfloor\frac{\lfloor\frac{N}{i^2}\rfloor}{d}\rfloor \end{aligned} \]get
而後就能夠把 \(m\) 的全部約數處理出來,暴力算(複雜度上界爲 \(O(T\sqrt \frac{n}{m} \sqrt m)\),實際後面的 \(\sqrt m\) 跑不滿)。string
注意\(\mu\)要篩到\(\sqrt N\)複雜度纔是對的(否則多一個根號)。it
#include <bits/stdc++.h> typedef long long LL; typedef unsigned long long uLL; #define SZ(x) ((int)x.size()) #define ALL(x) (x).begin(), (x).end() #define MP(x, y) std::make_pair(x, y) #define DEBUG(...) fprintf(stderr, __VA_ARGS__) #define GO cerr << "GO" << endl; using namespace std; inline void proc_status() { ifstream t("/proc/self/status"); cerr << string(istreambuf_iterator<char>(t), istreambuf_iterator<char>()) << endl; } template<class T> inline T read() { register T x(0); register char c; register int f(1); while (!isdigit(c = getchar())) if (c == '-') f = -1; while (x = (x << 1) + (x << 3) + (c xor 48), isdigit(c = getchar())); return x * f; } template<typename T> inline bool chkmin(T &a, T b) { return a > b ? a = b, 1 : 0; } template<typename T> inline bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; } const int maxN = 1e5; bool vis[maxN + 1]; vector<int> prime; int mu[maxN + 1]; LL n, m; void Init() { mu[1] = 1; for (int i = 2; i <= maxN; ++i) { if (!vis[i]) { prime.push_back(i); mu[i] = -1; } for (int j = 0; j < SZ(prime) and prime[j] * i <= maxN; ++j) { vis[prime[j] * i] = 1; if (i % prime[j] == 0) break; else mu[i * prime[j]] = -mu[i]; } } } int Mu(LL M) { if (M <= maxN) return mu[M]; //GO; int cnt = 0; for (LL i = 2; i * i <= M; ++i) if (M % i == 0) { M /= i; cnt++; if (M % i == 0) return 0; } if (M != 1) cnt++; return (cnt & 1) ? -1 : 1; } vector<pair<LL, int> > p; LL calc(LL i) { LL ans(0); for (int l = 0; l < SZ(p); ++l) ans += (LL)p[l].second * (((n / m) / (i * i)) / p[l].first); return ans; } void GetP(LL m) { p.clear(); for (LL d = 1; d * d <= m; ++d) if (m % d == 0) { p.push_back(MP(d, Mu(d))); if (m / d == d) continue; p.push_back(MP(m / d, Mu(m / d))); } } void Solve() { int T = read<int>(); while (T--) { n = read<LL>(), m = read<LL>(); GetP(m); LL ans(0); for (LL i = 1; i * i <= (n / m); ++i) if (__gcd((LL)i, m) == 1) ans += Mu(i) * calc(i); ans *= Mu(m); printf("%lld\n", ans); } } int main() { #ifndef ONLINE_JUDGE freopen("xhc.in", "r", stdin); freopen("xhc.out", "w", stdout); #endif Init(); Solve(); return 0; }