Luogu P4450 双亲数

Description:

给定 \(A,B,d\) ,求满足$1\le a\le A,1\le b\le B $ 且 \(\gcd(a,b)=d\) 的数对数

Solution

考虑莫比乌斯反演
原式可化为

\[\sum_{i=1}^A\sum_{j=1}^B\gcd(i,j)=d \]

根据套路,我们先给两边除以 \(d\),化成

\[\sum_{i=1}^{\left\lfloor\tfrac A d\right\rfloor}\sum_{j=1}^{\left\lfloor\tfrac B d\right\rfloor}\gcd(i,j)=1 \]

为什么要化成这个形式呢?
因为根据莫比乌斯函数的性质

\[\sum_{d\mid n} \mu(d) = [n=1] \]

这个式子可以化成

\[\sum_{i=1}^{\left\lfloor\tfrac A d\right\rfloor}\sum_{j=1}^{\left\lfloor\tfrac B d\right\rfloor}\sum_{k\mid \gcd(i,j)} \mu(k) \]

我们考虑交换枚举顺序,先枚举 \(d\),原式就可以化成

\[\sum_{k=1}^{\min(\frac A d,\frac B d)} \mu(k)\sum_{i=1}^{\left\lfloor\tfrac A d\right\rfloor}\sum_{j=1}^{\left\lfloor\tfrac B d\right\rfloor} [k\mid\gcd(i,j)] \]

\[\sum_{k=1}^{\min(\frac A d,\frac B d)}\mu(k)\left\lfloor\tfrac A {kd}\right\rfloor\left\lfloor\tfrac B {kd}\right\rfloor \]

对于这个式子,\(\mu\) 函数可以线性预处理,分数可以用整除分块来做,时间复杂度是\(\Theta(\sqrt n)\)

Code

/*If you are full of hope,you will be invincible*/
#include <ctime>
#include <cstdio>
#include <random>
#include <cstring>
#include <iostream>
#include <algorithm>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>
#include<ext/pb_ds/priority_queue.hpp>
#define ri register int
typedef long long ll;
std::mt19937 hpy(time(nullptr)+(unsigned long long)(new char));
namespace IO{
	constexpr int HL=1<<20;
	char buf[HL],*t1=buf,*t2=buf;
	#ifndef ONLINE_JUDGE
	#define getc() getchar()
	#else
	#define getc() t1==t2&&(t2=(t1=buf)+fread(buf,1,HL,stdin),t1==t2)?EOF:*t1++
	#endif
	inline int read(){static int an,f;an = 0,f = 1;static char ch;ch=getc();
	while(!isdigit(ch))ch=='-'?f=-1:1,ch=getc();
	while(isdigit(ch))an=(an<<3)+(an<<1)+(ch^48),ch=getc();
	return an*f;}
	char buff[HL],*T=buff;
	void flush(){fwrite(buff,1,T-buff,stdout);T=buff;}
	inline void putc(char ch){if(T==buff+HL)flush();*T++=ch;}
	template<typename Tp>
	inline void print(Tp x){if(x<0)putc('-'),x=-x;if(!x)return putc('0'),void();
	static int st[20],tp;while(x)st[++tp]=x%10,x/=10;while(tp)putc(st[tp]^48),--tp;}
}
using IO::read;
using IO::print;
using IO::putc;
constexpr int inf = 0x3f3f3f3f,N = 1e6 + 10;
int vis[N],n,m,cnt;
ll pri[N],sum[N],mu[N];
inline void Sieve() {
	mu[1] = 1;
	for(ri i = 2;i <= N;++i) {
		if(!vis[i]) vis[i] = 1,pri[++cnt] = i,mu[i] = -1; 
		for(ri j = 1;j <= cnt && i*pri[j] <= N;++j) {
			vis[i*pri[j]] = 1;
			if(i%pri[j] == 0) break;
			mu[i*pri[j]] = -mu[i];
		}
	}//线性筛μ
	for(ri i = 1;i <= N;++i) sum[i] = mu[i] + sum[i-1];//用前缀和处理 
}
ll Solve(int a,int b,int d){
	int mx = std::min(a,b);
	ll ans = 0;
	for(ri l = 1,r;l <= mx;l = r + 1) {//整除分块
		r = std::min(a/(a/l),b/(b/l));
		ans += (sum[r]-sum[l-1])*(1ll*a/(1ll*l*d)) * (1ll*b/(1ll*l*d));
	}
	return ans;
}
int main() {
	Sieve();
	int a=read(),b=read(),d=read();
	print(Solve(a,b,d));
    return IO::flush(),0;
}
posted @ 2021-07-21 11:17  feicheng  阅读(33)  评论(0编辑  收藏  举报