题目描述
设为的约数个数,给定、,求
题目分析
首先很不显然的有这样一个结论:
证明如下
将一个数唯一质因数分解为,其约数个数为
考虑一个质数对的影响,假设分解质因数后有个,分解质因数后有个,则产生的贡献即为,接下来是关键的一步(反正我想不到XD)
(此句可自行忽略:只有当时才会有值,这就相当于一个的矩形,只取了左下角的字型的一块)
根据乘法原理,有
因为必须满足所有才会对答案造成贡献,则可以变形为
所以
(以上证明摘自:传送门)
证毕
现在就有了
根据数论中切换枚举次序的套路以及莫比乌斯反演对布尔条件框的替换,我们得到
于是这里使用分块优化,预处理的前缀和
最后考虑后面的两个Sigma怎么处理
可以观察发现它们都是的形式,此处可以用分块优化预处理
其实还可以预处理,可以发现
显然是约数个数和的前缀和函数,于是线性筛出与,求出前缀和即可
每次询问, 预处理,总时间复杂度为
TIPS
线性筛约数个数时存一下最小的质数的次方,即存下就可以方便的线性筛了
线性筛约数和同理,存一下最小的质数所对应的首项为,公比为,项数为的等比数列,即存下就可以愉快的线性筛了
AC code
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 100001;
namespace Mobius
{
#define LL long long
int Prime[MAXN], Cnt, mu[MAXN], d[MAXN], Minseq[MAXN];
bool IsnotPrime[MAXN];
LL sum_MU[MAXN], sum_D[MAXN];
void init()
{
mu[1] = d[1] = Minseq[1] = 1;
for(int i = 2; i < MAXN; ++i)
{
if(!IsnotPrime[i])
Prime[++Cnt] = i, mu[i] = -1, d[i] = Minseq[i] = 2;
for(int j = 1; j <= Cnt && i * Prime[j] < MAXN; ++j)
{
IsnotPrime[i * Prime[j]] = 1;
if(i % Prime[j] == 0)
{
Minseq[i * Prime[j]] = Minseq[i]+1;
mu[i * Prime[j]] = 0;
d[i * Prime[j]] = d[i] / Minseq[i] * Minseq[i * Prime[j]];
break;
}
Minseq[i * Prime[j]] = 2;
mu[i * Prime[j]] = -mu[i];
d[i * Prime[j]] = d[i]<<1;
}
}
for(int i = 1; i < MAXN; ++i)
sum_MU[i] = sum_MU[i-1] + mu[i],
sum_D[i] = sum_D[i-1] + d[i];
}
LL calc(int N, int M)
{
if(N > M) swap(N, M);
LL ret = 0;
for(int i = 1, j; i <= N; i=j+1)
{
j = min(N/(N/i), M/(M/i));
ret += (sum_MU[j]-sum_MU[i-1]) * sum_D[N/i] * sum_D[M/i];
}
return ret;
}
}
using namespace Mobius;
int main ()
{
init();
int T, n, m;
scanf("%d", &T);
while(T--)
{
scanf("%d%d", &n, &m);
printf("%lld\n", calc(n, m));
}
}