求 (sumlimits_{i=x}^nsumlimits_{j=y}^m [(i,j)=k])。
根据容斥原理,可以把原始拆成形式相同的四个柿子进行计算。(以下均假设 (n<m),且所有除法均为下取整)
[egin{aligned}
sumlimits_{i=1}^nsumlimits_{j=1}^m [(i,j)=k]&=sumlimits_{i=1}^{n/k}sumlimits_{j=1}^{m/k}[(i,j)=1]
\&=sumlimits_{i=1}^{n/k}sumlimits_{j=1}^{m/k}sumlimits_{p|i,j}mu(p)
\&=sumlimits_{p=1}^{n/k}mu(p)lfloor frac{n}{pk}
floorlfloorfrac{m}{pk}
floor
end{aligned}
]
直接数论分块即可。
代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
const int N=50000;
int A,B,C,D,k;
int a[N+9],p[N+9],cnt,u[N+9];
void prime()
{
u[1]=1;
for (int i=2;i<=N;i++)
{
if(!a[i])
a[i]=i,p[++cnt]=i,u[i]=-1;
for (int j=1;j<=cnt;j++)
{
if(p[j]>N/i||p[j]>a[i])
break;
a[p[j]*i]=p[j];
if(i%p[j])
u[p[j]*i]=u[i]*u[p[j]];
}
}
for (int i=1;i<=N;i++)
u[i]+=u[i-1];
}
int calc(int A,int B)
{
A=A/k,B=B/k;
int Min=min(A,B),ans=0;
for (int i=1;i<=Min;i++)
{
int j=(A/(A/i)),k=(B/(B/i)),l=min(j,k);
ans+=(A/i)*(B/i)*(u[l]-u[i-1]);
i=l;
}
return ans;
}
void init()
{
scanf("%d %d %d %d %d",&A,&B,&C,&D,&k);
}
void work()
{
int T;
scanf("%d",&T);
while(T--)
{
init();
printf("%d
",calc(B,D)-((calc(A-1,D)+calc(B,C-1)-calc(A-1,C-1))));
}
}
int main()
{
prime();
work();
return 0;
}