题解 P2522 【[HAOI2011]Problem b】

对于给出的 n n n 个询问,每次求有多少个数对 ( x , y ) (x,y) (x,y),满足 a ≤ x ≤ b a \le x \le b axb c ≤ y ≤ d c \le y \le d cyd,且 gcd ⁡ ( x , y ) = k \gcd(x,y) = k gcd(x,y)=k gcd ⁡ ( x , y ) \gcd(x,y) gcd(x,y) 函数为 x x x y y y 的最大公约数。

前置知识

∑ i = a b ∑ j = c d [ gcd ⁡ ( i , j ) = k ] \sum\limits_{i=a}^{b} \sum\limits_{j=c}^{d} [\gcd(i,j)=k] i=abj=cd[gcd(i,j)=k]

函数 f ( x , y ) f(x,y) f(x,y) 为:

∑ i = 1 x ∑ j = 1 y [ gcd ⁡ ( i , j ) = k ] \sum\limits_{i=1}^{x} \sum\limits_{j=1}^{y} [\gcd(i,j)=k] i=1xj=1y[gcd(i,j)=k]

那么,运用容斥原理,原式就 = f ( b , d ) − f ( a , d ) − f ( b , c ) + f ( a , c ) = f(b,d) - f(a,d) - f(b,c) + f(a,c) =f(b,d)f(a,d)f(b,c)+f(a,c)

所以现在问题就转换为了求 f f f 函数。

∑ i = 1 x ∑ j = 1 y [ gcd ⁡ ( i , j ) = k ] = ∑ i = 1 ⌊ n k ⌋ ∑ j = 1 ⌊ m k ⌋ [ gcd ⁡ ( i , j ) = 1 ] = ∑ i = 1 ⌊ n k ⌋ ∑ j = 1 ⌊ m k ⌋ ε ( gcd ⁡ ( i , j ) ) = ∑ i = 1 ⌊ n k ⌋ ∑ j = 1 ⌊ m k ⌋ ∑ d ∣ gcd ⁡ ( i , j ) μ ( d ) = ∑ d = 1 μ ( d ) ∑ i = 1 ⌊ n k ⌋ [ d ∣ i ] ∑ j = 1 ⌊ m k ⌋ [ d ∣ j ] = ∑ d = 1 μ ( d ) ⌊ n k d ⌋ ⌊ m k d ⌋ \begin{aligned} &\sum\limits_{i=1}^{x} \sum\limits_{j=1}^{y} [\gcd(i,j)=k] \\ =& \sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{k}\rfloor}[\gcd(i,j)=1]\\ =& \sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{k}\rfloor}\varepsilon(\gcd(i,j))\\ =& \sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{k}\rfloor}\sum_{d \mid \gcd(i,j) }\mu(d)\\ =& \sum_{d=1 }\mu(d)\sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}[d \mid i]\sum_{j=1}^{\lfloor\frac{m}{k}\rfloor}[d \mid j]\\ =&\sum_{d=1}\mu(d)\lfloor\frac{n}{kd}\rfloor\lfloor\frac{m}{kd}\rfloor \end{aligned} =====i=1xj=1y[gcd(i,j)=k]i=1knj=1km[gcd(i,j)=1]i=1knj=1kmε(gcd(i,j))i=1knj=1kmdgcd(i,j)μ(d)d=1μ(d)i=1kn[di]j=1km[dj]d=1μ(d)kdnkdm

我们可以使用数论分块进行求解

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>inline void read(T &FF){
	T RR=1;FF=0;char CH=getchar();
	for(;!isdigit(CH);CH=getchar())if(CH=='-')RR=-1;
	for(;isdigit(CH);CH=getchar())FF=(FF<<1)+(FF<<3)+(CH^48);
	FF*=RR;
}
const int N=50010;
int prim[N],mu[N],sum[N],cnt,k,T;
bool vis[N];
void init(){
	mu[1]=1;
	for(register int i=2;i<N;i++){
		if(!vis[i]){
			mu[i]=-1;
			prim[++cnt]=i;
		}
		for(register int j=1;j<=cnt&&i*prim[j]<N;j++){
			vis[i*prim[j]]=1;
			if(i%prim[j]==0)break;
			mu[i*prim[j]]=-mu[i];
		}
	}
	for(register int i=1;i<N;i++)sum[i]=sum[i-1]+mu[i];
}//莫比乌斯反演的板子
ll calc(int a,int b){
	ll ans=0;
	for(register int l=1,r;l<=min(a,b);l=r+1){
		r=min(a/(a/l),b/(b/l));
		ans+=(1ll*a/l)*(1ll*b/l)*(sum[r]-sum[l-1]);
	}
	return ans;
}
int main(){
	init();
	for(read(T);T--;){
		int a,b,c,d;
		read(a);read(b);read(c);read(d);read(k);
		a--;c--;a/=k;b/=k;c/=k;d/=k;
		printf("%lld\n",calc(b,d)-calc(b,c)-calc(a,d)+calc(a,c));
	}
	return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值