【题目】
题目描述:
对于给出的 n n n 个询问,每次求有多少个数对 ( x , y ) (x,y) (x,y),满足 a ≤ x ≤ b a≤x≤b a≤x≤b, c ≤ y ≤ d c≤y≤d c≤y≤d,且 gcd ( x , y ) = k \gcd(x,y) = k gcd(x,y)=k, gcd ( x , y ) \gcd(x,y) gcd(x,y) 函数为 x x x 和 y y y 的最大公约数。
输入格式:
第一行一个整数 n n n,接下来 n n n 行每行五个整数,分别表示 a a a、 b b b、 c c c、 d d d、 k k k。
输出格式:
共 n n n 行,每行一个整数表示满足要求的数对 ( x , y ) (x,y) (x,y) 的个数。
样例数据:
输入
2
2 5 1 5 1
1 5 1 5 2
输出
14
3
说明:
100 % 100\% 100% 的数据满足: 1 ≤ n ≤ 50000 1≤n≤50000 1≤n≤50000, 1 ≤ a ≤ b ≤ 50000 1≤a≤b≤50000 1≤a≤b≤50000, 1 ≤ c ≤ d ≤ 50000 1≤c≤d≤50000 1≤c≤d≤50000, 1 ≤ k ≤ 50000 1≤k≤50000 1≤k≤50000
【分析】
题目要我们求的就是
∑ i = a b ∑ j = c d [    gcd ( i , j ) = k    ] \sum_{i=a}^b\sum_{j=c}^d[\;\gcd(i,j)=k\;] i=a∑bj=c∑d[gcd(i,j)=k]
容斥一下,得到
∑ i = 1 b ∑ j = 1 d [    gcd ( i , j ) = k    ] + ∑ i = 1 a − 1 ∑ j = 1 c − 1 [    gcd ( i , j ) = k    ] \sum_{i=1}^b\sum_{j=1}^d[\;\gcd(i,j)=k\;]+\sum_{i=1}^{a-1}\sum_{j=1}^{c-1}[\;\gcd(i,j)=k\;] i=1∑bj=1∑d[gcd(i,j)=k]+i=1∑a−1j=1∑c−1[gcd(i,j)=k] − ∑ i = 1 a − 1 ∑ j = 1 d [    gcd ( i , j ) = k    ] − ∑ i = 1 b ∑ j = 1 c − 1 [    gcd ( i , j ) = k    ] -\sum_{i=1}^{a-1}\sum_{j=1}^d[\;\gcd(i,j)=k\;]-\sum_{i=1}^b\sum_{j=1}^{c-1}[\;\gcd(i,j)=k\;] −i=1∑a−1j=1∑d[gcd(i,j)=k]−i=1∑bj=1∑c−1[gcd(i,j)=k]
发现这是四个一模一样的子问题,我们只需处理
∑ i = 1 n ∑ j = 1 m [    gcd ( i , j ) = k    ] \sum_{i=1}^n\sum_{j=1}^m[\;\gcd(i,j)=k\;] i=1∑nj=1∑m[gcd(i,j)=k]
剩下的部分就和ZAP这道题一样了,就不多说了。
【代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 50005
using namespace std;
int prime[N],mu[N];
bool mark[N];
void linear_sieves()
{
int i,j,sum=0;
memset(mark,true,sizeof(mark));
mark[0]=mark[1]=false,mu[1]=1;
for(i=2;i<N;++i)
{
if(mark[i]) prime[++sum]=i,mu[i]=-1;
for(j=1;j<=sum&&i*prime[j]<N;++j)
{
mark[i*prime[j]]=false;
if(i%prime[j]) mu[i*prime[j]]=-mu[i];
else break;
}
}
for(i=1;i<N;++i) mu[i]+=mu[i-1];
}
int solve(int a,int b,int k)
{
a/=k,b/=k;
int i,j,ans=0;
if(a>b) swap(a,b);
for(i=1;i<=a;i=j+1)
{
j=min(a/(a/i),b/(b/i));
ans+=(mu[j]-mu[i-1])*(a/i)*(b/i);
}
return ans;
}
int main()
{
int n,i;
scanf("%d",&n);
linear_sieves();
int a,b,c,d,k;
for(i=1;i<=n;++i)
{
scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
printf("%d\n",solve(b,d,k)+solve(a-1,c-1,k)-solve(a-1,d,k)-solve(b,c-1,k));
}
return 0;
}