小 D 是一名数学爱好者,他对数字的着迷到了疯狂的程度。
我们以 d = gcd(a, b) 表示 a 、b 的最大公约数,小D执著的认为,这样亲密的关系足可以用双亲来描述,此时,我们称有序数对 (a, b) 为d的双亲数。
与正常双亲不太相同的是,对于同一个 d ,他的双亲太多了 >_<
比如, (4, 6), (6, 4), (2, 100) 都是 2 的双亲数。
于是一个这样的问题摆在眼前,对于 0<a<=A, 0<b<=B ,有多少有序数对 (a, b) 是 d 的双亲数?
看完题目,就知道了是要求这个式子
\[\sum_{a=1}^A\sum_{b=1}^B\ [gcd(a,b)=d]
\]
考虑莫反,设\(f(x)=\begin{cases}\ 1&(x=d)&\\\ 0&(x\ne d)&\end{cases}\)
那么我们要找到一个\(g\)使得\(f=g*1\),即\(f(x)=\sum_{k|x}g(x)\),因为\(1\)的逆是\(\mu\),所以\(g=f*\mu\)
\[g(x)=\sum_{k|x}\mu(\frac{x}{k})[k=d]
\]
\[g(x)=\mu(\frac{x}{d})[d|x]
\]
假设我们已经求出来\(g\),那么就可以对式子进行化简了
\[\sum_{a=1}^A\sum_{b=1}^B\ f(gcd(a,b))
\]
\[\sum_{a=1}^A\sum_{b=1}^B\sum_{k|a,k|b}\ g(k)
\]
\[\sum_{k=1}^{min(A,B)}g(k)\ \sum_{a=1}^A\sum_{b=1}^B\ [k|a]\ [k|b]
\]
\[\sum_{k=1}^{min(A,B)}g(k)\ \lfloor\frac{A}{k}\rfloor\ \lfloor\frac{B}{k}\rfloor
\]
然后对这个式子整除分块就可以了
至于\(g\)怎么求,我们把\(\mu\)筛出来,然后就可以求每个\(g(x)\),再做一个前缀和就可以\(O(1)\)询问区间\(g\)的和了
Code
#include <iostream>
#include <cstdio>
#define N 1000000
using namespace std;
int a,b,d,mul[N+5],v[N+5],prime[N+5],cnt,g[N+5],sg[N+5];
long long ans;
void make()
{
mul[1]=1;v[1]=1;
for (int i=2;i<=N;i++) //线筛筛μ
{
if (!v[i])
{
prime[++cnt]=i;
mul[i]=-1;
}
for (int j=1;j<=cnt&&i*prime[j]<=N;j++)
{
v[prime[j]*i]=1;
if (i%prime[j]!=0)mul[i*prime[j]]=-mul[i];
else
{
mul[i*prime[j]]=0;
break;
}
}
}
for (int i=1;i<=N;i++) //处理g函数
if (i%d==0)
g[i]=mul[i/d];
for (int i=1;i<=N;i++) //前缀和
sg[i]=sg[i-1]+g[i];
}
int main()
{
cin>>a>>b>>d;
make();
if (a>b)swap(a,b);
for (int l=1,r;l<=a;l=r+1) 整除分块
{
r=min(a/(a/l),b/(b/l));
ans+=(sg[r]-sg[l-1])*1LL*(a/l)*1LL*(b/l)*1LL;
}
cout<<ans<<endl;
return 0;
}
常数大,代码丑(╯︵╰)****