【洛谷P2522】Problem b

题目

题目链接:https://www.luogu.com.cn/problem/P2522
对于给出的 \(n\) 个询问,每次求有多少个数对 \((x,y)\),满足 \(a \le x \le b\)\(c \le y \le d\),且 \(\gcd(x,y) = k\)\(\gcd(x,y)\) 函数为 \(x\)\(y\) 的最大公约数。

思路

把每次询问拆成 4 个,那么久转换成了有多少个 \(1\leq n\leq x,1\leq y\leq m\) 的数对满足 \(\gcd(x,y)=k\)
\(f(i)\) 表示 \(gcd(x,y)=i\) 的方案数,\(F(i)\) 表示 \(\gcd(x,y)\)\(i\) 的倍数的方案数。则 \(F(i)=\left \lfloor \frac{n}{i} \right \rfloor\left \lfloor \frac{m}{i} \right \rfloor\)
那么有

\[f(i)=\sum^{}_{x|y}\mu(\frac{y}{x})\left \lfloor \frac{n}{y} \right \rfloor\left \lfloor \frac{m}{y} \right \rfloor \]

\(i=\frac{x}{y}\),则

\[=\sum^{\min(n,m)}_{i=1}\mu(i)\left \lfloor \frac{n}{ix} \right \rfloor\left \lfloor \frac{m}{ix} \right \rfloor \]

预处理 \(\mu\),整除分块即可。
时间复杂度 \(O(A+n\sqrt{A})\),其中 \(A=\max(a,b,c,d)\)

代码

#include <bits/stdc++.h>
using namespace std;

const int N=50010;
int Q,m,a,b,c,d,k,prm[N],mu[N],sum[N];
bool v[N];

void findprm(int n)
{
	mu[1]=1;
	for (int i=2;i<=n;i++)
	{
		if (!v[i])
		{
			prm[++m]=i;
			mu[i]=-1;
		}
		for (int j=1;j<=m;j++)
		{
			if (i>n/prm[j]) break;
			v[prm[j]*i]=1; mu[prm[j]*i]=-mu[i];
			if (i%prm[j]==0)
			{
				mu[prm[j]*i]=0;
				break;
			}
		}
	}
}

int solve(int n,int m,int k)
{
	int cnt=0;
	for (int l=1,r;l*k<=min(n,m);l=r+1)
	{
		r=min(n/(n/l),m/(m/l));
		cnt+=(sum[r]-sum[l-1])*(n/l/k)*(m/l/k);
	}
	return cnt;
}

int main()
{
	findprm(N-1);
	for (int i=1;i<N;i++)
		sum[i]=sum[i-1]+mu[i];
	scanf("%d",&Q);
	while (Q--)
	{
		scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
		printf("%d\n",solve(b,d,k)-solve(b,c-1,k)-solve(a-1,d,k)+solve(a-1,c-1,k));
	}
	return 0;
}
posted @ 2020-09-25 14:25  stoorz  阅读(137)  评论(0编辑  收藏  举报