莫反+数论分块+前缀和
4.HDU4746 Mophues
题目描述
给Q ( 1 ≤ Q ≤ 5000 ) Q(1\le Q\le 5000) Q ( 1 ≤ Q ≤ 5 0 0 0 ) 个询问,每个询问给出n , m , p n,m,p n , m , p 求∑ i = 1 N ∑ j = 1 M [ h ( g c d ( i , j ) ) < = p ] \sum\limits_{i=1}^N\sum\limits_{j=1}^M[h(gcd(i,j))<=p] i = 1 ∑ N j = 1 ∑ M [ h ( g c d ( i , j ) ) < = p ] 。
题目分析
因为把数据范围内的数字分解,p最多为19,那么18 ≤ p 18\le p 1 8 ≤ p 时直接输出n ∗ m n*m n ∗ m ,对于另一种情况,令f ( x ) = ∑ i = 1 N ∑ j = 1 M [ g c d ( i , j ) = x ] f(x)=\sum\limits_{i=1}^N\sum\limits_{j=1}^M[gcd(i,j)=x] f ( x ) = i = 1 ∑ N j = 1 ∑ M [ g c d ( i , j ) = x ] ,那么答案就是∑ 1 ≤ x ≤ n , h ( x ) ≤ p f ( x ) \sum\limits_{1\le x\le n,h(x)\le p}f(x) 1 ≤ x ≤ n , h ( x ) ≤ p ∑ f ( x ) ,要求f ( x ) f(x) f ( x ) ,考虑莫比乌斯反演,定义g ( x ) = ∑ i = 1 n ∑ j = 1 m [ x ∣ g c d ( i , j ) ] g(x)=\sum\limits_{i=1}^{n}\sum\limits_{j=1}^m[x|gcd(i,j)] g ( x ) = i = 1 ∑ n j = 1 ∑ m [ x ∣ g c d ( i , j ) ] ,易得所有的i , j i,j i , j 为x的倍数,那就很容易求出来g ( x ) = n x m x g(x)=\frac{n}{x}\frac{m}{x} g ( x ) = x n x m ,同时有g ( x ) = ∑ x ∣ y f ( y ) g(x)=\sum\limits_{x|y}f(y) g ( x ) = x ∣ y ∑ f ( y ) ,通过倍数形式的莫反得到f ( x ) = ∑ x ∣ y μ ( y / x ) ∗ g ( y ) = ∑ x ∣ y μ ( y / x ) ( n / y ) ∗ ( m / y ) f(x)=\sum\limits_{x|y}\mu(y/x)*g(y)=\sum\limits_{x|y}\mu(y/x)(n/y)*(m/y) f ( x ) = x ∣ y ∑ μ ( y / x ) ∗ g ( y ) = x ∣ y ∑ μ ( y / x ) ( n / y ) ∗ ( m / y ) .那么答案为
∑ 1 ≤ x ≤ n , h ( x ) ≤ p ∑ x ∣ y μ ( y / x ) ( n / y ) ( m / y ) = ∑ 1 ≤ x ≤ n , h ( x ) ≤ p ∑ 1 ≤ k ≤ n / x μ ( k ) ( n / x k ) ( m / x k ) = ∑ 1 ≤ x ≤ n , h ( x ) ≤ p ∑ 1 ≤ k ≤ n / x μ ( k ) ( n / x k ) ( m / x k ) 交 换 求 和 顺 序 = ∑ 1 ≤ T ≤ n ( n / T ) ( m / T ) ∑ x ∣ T μ ( T / x ) [ h ( x ) ≤ p ] \sum\limits_{1\le x\le n,h(x)\le p}\sum\limits_{x|y}\mu(y/x)(n/y)(m/y)
\\=\sum\limits_{1\le x\le n,h(x)\le p}\ \sum\limits_{1\le k\le n/x}\mu(k)(n/xk)(m/xk)
\\=\sum\limits_{1\le x\le n,h(x)\le p}\ \sum\limits_{1\le k\le n/x}\mu(k)(n/xk)(m/xk)
\\交换求和顺序
\\=\sum\limits_{1\le T\le n}(n/T)(m/T) \sum\limits_{x|T}\mu(T/x)[h(x)\le p]
1 ≤ x ≤ n , h ( x ) ≤ p ∑ x ∣ y ∑ μ ( y / x ) ( n / y ) ( m / y ) = 1 ≤ x ≤ n , h ( x ) ≤ p ∑ 1 ≤ k ≤ n / x ∑ μ ( k ) ( n / x k ) ( m / x k ) = 1 ≤ x ≤ n , h ( x ) ≤ p ∑ 1 ≤ k ≤ n / x ∑ μ ( k ) ( n / x k ) ( m / x k ) 交 换 求 和 顺 序 = 1 ≤ T ≤ n ∑ ( n / T ) ( m / T ) x ∣ T ∑ μ ( T / x ) [ h ( x ) ≤ p ]
然后通过一些妙哇的筛法求出来后面的一坨东西。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 #include <vector> #include <algorithm> #include <iostream> #include <array> using ll = long long ;int main () { std::ios::sync_with_stdio (false ); std::cin.tie (nullptr ); std::cout.tie (nullptr ); std::vector<int > prime, vis (5e5 + 10 ), mu (5e5 + 10 ), h (5e5 + 10 ); mu[1 ] = 1 , h[1 ] = 0 ; for (int i = 2 ; i <= 5e5 ; ++i) { if (!vis[i])prime.push_back (i), mu[i] = -1 , h[i] = 1 ; for (int j = 0 ; j < prime.size () && i * prime[j] <= 5e5 ; ++j) { vis[i * prime[j]] = 1 ; h[prime[j] * i] = h[i] + 1 ; if (i % prime[j]) { mu[i * prime[j]] = -mu[i]; } else { mu[i * prime[j]] = 0 ; break ; } } } std::vector<std::array<ll, 20>> pref (5e5 + 10 ); for (int i = 1 ; i <= 5e5 ; ++i) { for (int k = 1 ; i * k <= 5e5 ; k++) { pref[i * k][h[i]] += mu[k]; } } for (int i = 0 ; i <= 5e5 ; ++i) for (int j = 1 ; j < 20 ; ++j)pref[i][j] += pref[i][j - 1 ]; for (int i = 1 ; i < 5e5 ; ++i)for (int j = 0 ; j < 20 ; ++j)pref[i][j] += pref[i - 1 ][j]; int q; std::cin >> q; while (q--) { ll n, m, p; std::cin >> n >> m >> p; if (p >= 18 ) { std::cout << n * m << '\n' ; } else { if (n > m)std::swap (n, m); ll ans = 0 ; for (ll l = 1 , r; l <= n; l = r + 1 ) { r = std::min (n / (n / l), m / (m / l)); ans += (pref[r][p] - pref[l - 1 ][p]) * (n / l) * (m / l); } std::cout << ans << '\n' ; } } return 0 ; }