BZOJ 3994 - [SDOI2015]约数个数和
Published on 2016-08-13描述
设 为 的约数个数,有 组询问,每次给定 ,求:
分析
首先有一个结论:
证明:设 ,且 ,则 。
设 ,,要使 ,必然有 或 为 0,如果 为 0,那么 有 种取值;如果 为 0,那么 有 种取值,一共有 种取值,对于 也如此。
所以满足条件的 对数为 ,与约数定理给出的形式一样,得证。
回到原式,我们化简一下,其中第二个等号用到了莫比乌斯函数的一个性质:
由于 是积性函数,所以可以 线筛预处理,至此式子转换为可以分块的形式,单组询问可以在: 的时间内解决。
复杂度:。
本题技巧性比较强,变换比较多,需要熟练掌握莫比乌斯的分块处理技巧,有什么问题可以直接留言。
代码
// Created by Sengxian on 8/13/16. // Copyright (c) 2016年 Sengxian. All rights reserved. // BZOJ 3994 莫比乌斯反演 + 线性筛 #include <bits/stdc++.h> using namespace std; typedef long long ll; inline int ReadInt() { static int n, ch; n = 0, ch = getchar(); while (!isdigit(ch)) ch = getchar(); while (isdigit(ch)) n = (n << 3) + (n << 1) + ch - '0', ch = getchar(); return n; } const int maxn = 50000 + 3; int primes[maxn], num; int mu[maxn], sigma[maxn], sumMu[maxn]; ll sumSigma[maxn]; bool isPrime[maxn]; void sieve() { static int minPrimeCnt[maxn]; fill(isPrime, isPrime + maxn, 1); mu[1] = 1, sigma[1] = 1, num = 0; for (int i = 2; i < maxn; ++i) { if (isPrime[i]) primes[num++] = i, mu[i] = -1, sigma[i] = 2, minPrimeCnt[i] = 1; static int d; for (int j = 0; j < num && (d = i * primes[j]) < maxn; ++j) { isPrime[d] = false; if (i % primes[j] == 0) { mu[d] = 0; minPrimeCnt[d] = minPrimeCnt[i] + 1; sigma[d] = sigma[i] / (minPrimeCnt[i] + 1) * (minPrimeCnt[d] + 1); break; } else mu[d] = -mu[i], sigma[d] = sigma[i] << 1, minPrimeCnt[d] = 1; } } sumMu[0] = 0; for (int i = 1; i < maxn; ++i) sumMu[i] += sumMu[i - 1] + mu[i]; for (int i = 1; i < maxn; ++i) sumSigma[i] += sumSigma[i - 1] + sigma[i]; } inline ll F(int n, int m) { if (n > m) swap(n, m); ll ans = 0; for (int i = 1, j = 1; i <= n; i = j + 1) { j = min(n / (n / i), m / (m / i)); ans += (sumMu[j] - sumMu[i - 1]) * sumSigma[n / i] * sumSigma[m / i]; } return ans; } int main() { sieve(); int caseNum = ReadInt(); while (caseNum--) { int n = ReadInt(), m = ReadInt(); printf("%lld\n", F(n, m)); } return 0; }