欢迎大家访问我的老师的OJ———caioj.cn
题面描述
注意,caioj题面略有不同
思路
与Zap很像。
设 D ( a , b , k ) D(a,b,k) D(a,b,k)表示满足 x ≤ a , y ≤ b x\le a,y\le b x≤a,y≤b且 k ∣ gcd ( x , y ) k \mid \gcd(x,y) k∣gcd(x,y)的二元组有多少对。
由于 D ( a , b , k ) = ⌊ a / k ⌋ ∗ ⌊ b / k ⌋ D(a,b,k)=\left\lfloor a/k\right\rfloor* \left\lfloor b/k\right\rfloor D(a,b,k)=⌊a/k⌋∗⌊b/k⌋
设 F ( a , b ) F(a,b) F(a,b)表示满足 x ≤ a , y ≤ b x\le a,y\le b x≤a,y≤b并且 x , y x,y x,y互质的二元组有多少对。
由于
F ( a , b ) = ∑ i = 1 min ( a , b ) μ ( i ) ∗ D ( a , b , i ) F(a,b)=\sum_{i=1}^{\operatorname{min}(a,b)}\mu(i)*D(a,b,i) F(a,b)=i=1∑min(a,b)μ(i)∗D(a,b,i)
那么我们现在多了 a ≤ x ≤ b , c ≤ y ≤ d a\le x\le b,c\le y\le d a≤x≤b,c≤y≤d这个限制。
从 F ( a , b ) F(a,b) F(a,b)的定义下手:满足 x ≤ a , y ≤ b x\le a,y\le b x≤a,y≤b并且 x , y x,y x,y互质的二元组有多少对
我们现在要求满足 a ≤ x ≤ b , c ≤ y ≤ d a\le x\le b,c\le y\le d a≤x≤b,c≤y≤d并且 x , y x,y x,y互质的二元组有多少对
我们转化一下条件:
满足 a ≤ x ≤ b , c ≤ y ≤ d a\le x\le b,c\le y\le d a≤x≤b,c≤y≤d并且 x , y x,y x,y互质的二元组有多少对 ↔ \leftrightarrow ↔
满足 x ≤ b , y ≤ d x\le b,y\le d x≤b,y≤d, x , y x,y x,y互质,且不满足 x < a x<a x<a或 y < c y<c y<c的二元组有多少对
那么我们就可以得到区间 F ( b , d ) , F ( a − 1 , c − 1 ) , F ( a − 1 , d ) , F ( b , c − 1 ) F(b,d),F(a-1,c-1),F(a-1,d),F(b,c-1) F(b,d),F(a−1,c−1),F(a−1,d),F(b,c−1)
其中 F ( a − 1 , d ) , F ( b , c − 1 ) F(a-1,d),F(b,c-1) F(a−1,d),F(b,c−1)就是分别 x < a , y < c x<a,y<c x<a,y<c的不符合题意的二元组数量,
根据容斥原理,因为 F ( a − 1 , d ) F(a-1,d) F(a−1,d)中所包含的二元组与 F ( b , c − 1 ) F(b,c-1) F(b,c−1)包含的二元组会有交集,交集重复算了两次,要去重
所以我们要相应的加上 F ( a − 1 , d ) ∩ F ( b , c − 1 ) F(a-1,d)\cap F(b,c-1) F(a−1,d)∩F(b,c−1),即 F ( a − 1 , c − 1 ) F(a-1,c-1) F(a−1,c−1)
所以答案就为:
F ( b , d ) + F ( a − 1 , c − 1 ) − F ( a − 1 , d ) − F ( b , c − 1 ) F(b,d)+F(a-1,c-1)-F(a-1,d)-F(b,c-1) F(b,d)+F(a−1,c−1)−F(a−1,d)−F(b,c−1)
AC code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#define ll long long
#define gc getchar()
using namespace std;
const int N=1e5+5;
const int inf=1e5;
const int M=5e4+5;
int n,prime[M],m,miu[N];bool v[N];
inline void qr(int &x)
{
x=0;int f=1;char c=gc;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc;}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=gc;}
x*=f;
}
void g_p()
{
m=0;memset(v,false,sizeof(v));miu[1]=1;
for(int i=2;i<=inf;i++)
{
if(!v[i])prime[++m]=i,miu[i]=-1;
for(int j=1;j<=m&&i*prime[j]<=inf;j++)
{
v[i*prime[j]]=1;
if(i%prime[j]==0){miu[i*prime[j]]=0;break;}
miu[i*prime[j]]=-miu[i];
}
}
for(int i=2;i<=inf;i++)miu[i]+=miu[i-1];
}
ll calc(int a,int b)
{
if(a>b)swap(a,b);
ll ans=0;
for(int x=1,gx;x<=a;x=gx+1)//分块
{
gx=min(a/(a/x),b/(b/x));
ans+=(ll)(miu[gx]-miu[x-1])*(a/x)*(b/x);
}
return ans;
}
int main()
{
g_p();
int t;qr(t);
while(t--)
{
int a,b,c,d,k;qr(a),qr(b),qr(c),qr(d),qr(k);a--;c--;
if(k==0){puts("0");continue;}
a/=k,b/=k,c/=k,d/=k;
ll ans=calc(a,c)+calc(b,d)-calc(a,d)-calc(b,c);
printf("%lld\n",ans);
}
return 0;
}