洛谷 P4450 双亲数

小 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;
}

常数大,代码丑(╯︵╰)****

posted @ 2020-06-08 20:11  eee_hoho  阅读(143)  评论(0编辑  收藏  举报