题意:对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数。
ans=sigma(1)(a<=x<=b,c<=y<=d, gcd(x,y)=k)
即 ans=sigma(1) (floor(a/k)<=x<=floor(b/k), floor(c/k)<=y<=floor(d/k) , gcd(x,y)=1)
根据容斥原理转化为:
ans=sigma(1)(1<=i<=floor(b/k),1<=j<=floor(d/k) ,gcd(i,j)=k)
-sigma(1) (1<=i<=floor(b/k) , 1<=j<=floor((c-1)/k), gcd(i,j)=k)
-sigma(1) (1<=i<=floor((a-1)/k)-1, 1<=j<=floor(d/k), gcd(i,j)=k)
+sigma(1) (1<=i<=floor((a-1)/k), 1<=j<=floor((c-1)/k) ,gcd(i,j)=k)
我们对其中任意一个sigma(1)处理,假设 sigma(1) (1<=i<=n,1<=j<=m,gcd(i,j)=1)
令f(i)表示范围内gcd(x,y)=i 的数对数, F(i)表示范围内 i能整除 gcd(x,y) 的数对数
易知 F(i) = floor(n/i)*floor(m/i)
由莫比乌斯反演得
f(i)=sigma(miu(d/i)*F(d)) (i能整除d)
=sigma(miu(d/i)* floor(n/d) * floor(m/d)) (i能整除d)
那么 sigma(1)= f(1)= sigma( miu(d)*floor(n/d) * floor( m/d)
枚举floor(n/d)*floor(m/d) 个取值,对莫比乌斯函数维护一个前缀和,计算出ans
强转int64就是快..
var
t,a,b,c,d,k :longint;
ans :int64;
flag :array[0..50010] of boolean;
prime :array[0..50010] of longint;
mu :array[0..50010] of longint;
function min(a,b:longint):longint;
begin
if a50000) then break else
begin
flag[i*prime[j]]:=true;
if (i mod prime[j]<>0) then mu[i*prime[j]]:=-mu[i] else
begin
mu[i*prime[j]]:=0;
break;
end;
end;
end;
for i:=1 to 50000 do mu[i]:=mu[i-1]+mu[i];
end;
function find(n,m:longint):int64;
var
i:longint;
ans,last:int64;
begin
ans:=0;
i:=1;
n:=n div k;m:=m div k;
while (i<=n) and (i<=m) do
begin
last:=min(n div (n div i),m div (m div i));
ans:=ans+int64(n div i)*int64(m div i)*(mu[last]-mu[i-1]);
i:=last+1;
end;
exit(ans);
end;
begin
pre_do;
read(t);
while (t>0) do
begin
dec(t);
read(a,b,c,d,k);
ans:=find(b,d)-find(a-1,d)-find(b,c-1)+find(a-1,c-1);
writeln(ans);
end;
end.
——by Eirlys