[HAOI2011]Problem b

洛谷题目链接

简单的数论题

我们需要求:$$\sum\limits_{i=a}^b \sum\limits_{j=c}^d [gcd(i,j)=k]$$

我们发现可以像二维前缀和一样容斥,所以我们只要会求下面的式子,上面的式子也就能解啦:$$\sum\limits_{i=1}^n \sum\limits_{j=1}^m [gcd(i,j)=k]$$

下面默认\(n<m\)

那么按照套路来吧:$$\sum\limits_{i=1}^{\left\lfloor \frac{n}{k} \right\rfloor} \sum\limits_{j=1}^{\left\lfloor \frac{m}{k} \right\rfloor} [gcd(i,j)=1]$$

莫比乌斯反演:$$\sum\limits_{i=1}^{\left\lfloor \frac{n}{k} \right\rfloor} \sum\limits_{j=1}^{\left\lfloor \frac{m}{k} \right\rfloor} \sum\limits_{d|gcd(i,j)} \mu (d)$$

枚举\(d\):$$ \sum\limits_{d=1}^{\left\lfloor \frac{n}{k} \right\rfloor} \mu (d) \sum\limits_{i=1}^{\left\lfloor \frac{n}{k} \right\rfloor} \sum\limits_{j=1}^{\left\lfloor \frac{m}{k} \right\rfloor} [d|gcd(i,j)]$$

除以\(d\):$$\sum\limits_{d=1}^{\left\lfloor \frac{n}{k} \right\rfloor} \mu (d) \sum\limits_{i=1}^{\left\lfloor \frac{n}{kd} \right\rfloor} \sum\limits_{j=1}^{\left\lfloor \frac{m}{kd} \right\rfloor} 1$$

发现后面可以用整除分块做:$$\sum\limits_{d=1}^{\left\lfloor \frac{n}{k} \right\rfloor} \mu (d) \left\lfloor \frac{n}{kd} \right\rfloor \left\lfloor \frac{m}{kd} \right\rfloor$$

这样我们就可以欢乐整除分块啦~~~

接下来是美滋滋的代码时间~~~

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 50007
using namespace std;
int T;
int a,b,c,d,k,cnt;
int mu[N],num[N],prime[N];
bool isp[N];
void Get_mu()
{
	mu[1]=1;
	for(int i=2;i<=N-7;++i)
	{
		if(!isp[i])
		{
			prime[++cnt]=i;
			mu[i]=-1;
		}
		for(int j=1;j<=cnt&&(i*prime[j])<=N-7;++j)
		{
			isp[i*prime[j]]=1;
			if(i%prime[j]==0)
				break;
			else
				mu[i*prime[j]]=-mu[i];
		}
	}
	for(int i=1;i<=N-7;++i)
		num[i]=num[i-1]+mu[i];
}
int Get(int n,int m,int k)
{
	if(n>m)
		swap(n,m);
	int nn=n/k;
	int ans=0;
	for(int l=1,r;l<=nn;l=r+1)
	{
		r=min((n/k)/(n/l/k),(m/k)/(m/l/k));
		ans+=(num[r]-num[l-1])*(n/l/k)*(m/l/k);
	}
	return ans;
}
int main()
{
	Get_mu();
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
		printf("%d\n",Get(b,d,k)-Get(a-1,d,k)-Get(c-1,b,k)+Get(a-1,c-1,k));
	}
	return 0;
}
posted @ 2019-07-11 18:52  模拟退火  阅读(136)  评论(0编辑  收藏  举报