题意
(n) 组询问,每组给定 (a,b,c,d,k),求 (sumlimits_{i=a}^{b}sumlimits_{j=c}^{d}[gcd(i,j)=k])。
( exttt{Data Range:}1leq n,kleq 5 imes 10^4,1leq aleq bleq 5 imes 10^4,1leq cleq dleq 5 imes 10^4)
题解
首先考虑二维差分一下,发现我们只需要求出类似于 (sumlimits_{i=1}^{n}sumlimits_{j=1}^{m}[gcd(i,j)=k]) 的东西就好了(这里的 (n) 不再是数据组数)
然后考虑推一下式子
[sumlimits_{i=1}^{n}sumlimits_{j=1}^{m}[gcd(i,j)=k]=sumlimits_{i=1}^{leftlfloorfrac{n}{k}
ight
floor}sumlimits_{j=1}^{leftlfloorfrac{m}{k}
ight
floor}[gcd(i,j)=1]
]
然后发现可以莫反一下
[sumlimits_{i=1}^{n}sumlimits_{j=1}^{m}[gcd(i,j)=k]=sumlimits_{i=1}^{leftlfloorfrac{n}{k}
ight
floor}sumlimits_{j=1}^{leftlfloorfrac{m}{k}
ight
floor}sumlimits_{dmidgcd(i,j)}mu(d)
]
然后交换一下求和变量得到
[sumlimits_{i=1}^{n}sumlimits_{j=1}^{m}[gcd(i,j)=k]=sumlimits_{dmidgcd(i,j)}mu(d)leftlfloorfrac{n}{dk}
ight
floorleftlfloorfrac{m}{dk}
ight
floor
]
然后线性筛一下 (mu) 的前缀和就可以整除分块做了。
代码
#include<bits/stdc++.h>
using namespace std;
typedef int ll;
typedef long long int li;
const ll MAXN=2e5+51;
ll ptot,n,u,v,w,x,kk;
ll np[MAXN],prime[MAXN],mu[MAXN],prefix[MAXN];
inline ll read()
{
register ll num=0,neg=1;
register char ch=getchar();
while(!isdigit(ch)&&ch!='-')
{
ch=getchar();
}
if(ch=='-')
{
neg=-1;
ch=getchar();
}
while(isdigit(ch))
{
num=(num<<3)+(num<<1)+(ch-'0');
ch=getchar();
}
return num*neg;
}
inline void sieve(ll limit)
{
np[1]=mu[1]=1;
for(register int i=2;i<=limit;i++)
{
if(!np[i])
{
prime[++ptot]=i,mu[i]=-1;
}
for(register int j=1;i*prime[j]<=limit;j++)
{
np[i*prime[j]]=1;
if(i%prime[j]==0)
{
mu[i*prime[j]]=0;
break;
}
mu[i*prime[j]]=-mu[i];
}
}
for(register int i=1;i<=limit;i++)
{
prefix[i]=prefix[i-1]+mu[i];
}
}
inline ll calc(ll n,ll m)
{
ll res=0;
for(register int l=1,r;l<=min(n,m);l=r+1)
{
r=min(n/(n/l),m/(m/l));
res+=(prefix[r]-prefix[l-1])*(n/l/kk)*(m/l/kk);
}
return res;
}
int main()
{
n=read(),sieve(2e5+10);
for(register int i=1;i<=n;i++)
{
u=read(),v=read(),w=read(),x=read(),kk=read();
printf("%d
",calc(v,x)-calc(u-1,x)-calc(v,w-1)+calc(u-1,w-1));
}
}