P3327 [SDOI2015]约数个数和
一句话题意:
求 \(\displaystyle\sum_{i=1}^{n}\sum_{j=1}^{m} d(ij)\)
题解:
首先 \(d\) 函数有个性质, \(d(i,j) == \displaystyle\sum_{x \mid i}\sum_{y\mid j} [gcd(i,j) == 1]\)
然后我们要求的就是 :
\(\displaystyle\sum_{i=1}^{n}\sum_{j=1}^{m}\sum_{x\mid i}\sum_{y\mid j} [gcd[i,j] == 1]\)
直接上莫比乌斯反演,变成:
\(\displaystyle\sum_{i=1}^{n}\sum_{j=1}^{m}\sum_{x\mid i}\sum_{y \mid j} \sum_{p\mid x,p\mid y} \mu(p)\)
考虑到这么多的枚举量不太好算,所以我们需要减少一下枚举量。
先枚举一下 \(x\) 和 \(y\) 试试,变成:
\(\displaystyle\sum_{x=1}^{n}\sum_{j=1}^{m}\sum_{x \mid i}\sum_{y\mid j}\sum_{p\mid x,p \mid y} \mu(p)\)
发现倒数第三个和倒数第四个其实求的是 \(1-n\) 中 \(x\) 的倍数,以及 \(1-m\) 中 \(y\) 的倍数。
就可以写成:
\(\displaystyle\sum_{x=1}^{n}\sum_{y=1}^{m}\lfloor {n\over x}\rfloor\lfloor{m \over j}\rfloor \sum_{p \mid x,p\mid j} \mu(p)\)
先枚举一下 \(p\) 试试,
\(\displaystyle\sum_{p=1}^{n}\mu(p) \sum_{x=1}^{n}[p\mid x]\sum_{j=1}^{m} [p\mid j] \lfloor {n\over x}\rfloor\lfloor{m\over j}\rfloor\)
中间那两个柿子还可以在化简一下变成:
\(\displaystyle\sum_{p=1}^{n}\mu(p)\sum_{x=1}^{n\over d}\sum_{y=1}^{y\over d} \lfloor{n\over px}\rfloor\lfloor{m\over py}\rfloor\)
把两个向下取整拆开变为:
\(\displaystyle\sum_{p=1}^{n}\mu(p)\sum_{x=1}^{n\over p} \lfloor{n\over px}\rfloor\sum_{j=1}^{m\over p}\lfloor{m\over py}\rfloor\)
设 \(g(n)\) 表示 \(\displaystyle\sum_{i=1}^{n} {n\over i}\)
那么上面的柿子可以写成 \(\displaystyle\sum_{p=1}^{n}\mu(p) g({n\over p}) g({m\over p})\)
对于 \(g\) 我们可以利用整除分块求出来,最后的柿子也要搞个整除分块,所以就是整除分块套整除分块(老千层饼了)
Code
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define LL long long
const int N = 50010;
int n,m,T,tot;
LL mu[N],sum[N],prime[N];
bool check[N];
inline int read()
{
int s = 0,w = 1; char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
while(ch >= '0' && ch <= '9'){s =s * 10+ch - '0'; ch = getchar();}
return s * w;
}
void YYCH()
{
mu[1] = 1;
for(int i = 2; i <= N-5; i++)
{
if(!check[i])
{
prime[++tot] = i;
mu[i] = -1;
}
for(int j = 1; j <= tot && i * prime[j] <= N-5; j++)
{
check[i * prime[j]] = 1;
if(i % prime[j] == 0)
{
mu[i * prime[j]] = 0;
break;
}
else
{
mu[i * prime[j]] = -mu[i];
}
}
}
for(int i = 2; i <= N-5; i++) mu[i] += mu[i-1]; //求mu的前缀和
for(int i = 1; i <= N-5; i++)
{
for(int l = 1, r; l <= i; l = r+1)//求g函数值
{
r = min(i,(i/(i/l)));
sum[i] += (r-(l-1)) * (i/l);
}
}
}
LL slove(int n,int m)
{
LL res = 0;
for(int l = 1, r; l <= n; l = r+1)//套个整除分块
{
r = min(n/(n/l),m/(m/l));
res += (mu[r]-mu[l-1]) * sum[n/l] * sum[m/l];
}
return res;
}
int main()
{
T = read(); YYCH();
while(T--)
{
n = read(); m = read();
if(n > m) swap(n,m);
printf("%lld\n",slove(n,m));
}
return 0;
}

浙公网安备 33010602011771号