洛谷题目链接
简单的数论题
我们需要求:$$sumlimits_{i=a}^b sumlimits_{j=c}^d [gcd(i,j)=k]$$
我们发现可以像二维前缀和一样容斥,所以我们只要会求下面的式子,上面的式子也就能解啦:$$sumlimits_{i=1}^n sumlimits_{j=1}^m [gcd(i,j)=k]$$
下面默认(n<m)
那么按照套路来吧:$$sumlimits_{i=1}^{leftlfloor frac{n}{k} ight floor} sumlimits_{j=1}^{leftlfloor frac{m}{k} ight floor} [gcd(i,j)=1]$$
莫比乌斯反演:$$sumlimits_{i=1}^{leftlfloor frac{n}{k} ight floor} sumlimits_{j=1}^{leftlfloor frac{m}{k} ight floor} sumlimits_{d|gcd(i,j)} mu (d)$$
枚举(d):$$ sumlimits_{d=1}^{leftlfloor frac{n}{k} ight floor} mu (d) sumlimits_{i=1}^{leftlfloor frac{n}{k} ight floor} sumlimits_{j=1}^{leftlfloor frac{m}{k} ight floor} [d|gcd(i,j)]$$
除以(d):$$sumlimits_{d=1}^{leftlfloor frac{n}{k} ight floor} mu (d) sumlimits_{i=1}^{leftlfloor frac{n}{kd} ight floor} sumlimits_{j=1}^{leftlfloor frac{m}{kd} ight floor} 1$$
发现后面可以用整除分块做:$$sumlimits_{d=1}^{leftlfloor frac{n}{k} ight floor} mu (d) leftlfloor frac{n}{kd} ight floor leftlfloor frac{m}{kd} ight floor$$
这样我们就可以欢乐整除分块啦~~~
接下来是美滋滋的代码时间~~~
#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
",Get(b,d,k)-Get(a-1,d,k)-Get(c-1,b,k)+Get(a-1,c-1,k));
}
return 0;
}