Problem Description
Given 5 integers: a, b, c, d, k, you're to find x in a...b, y in c...d that GCD(x, y) = k. GCD(x, y) means the greatest common divisor of x and y. Since the number of choices may be very large, you're only required to output the total number of different number pairs.
Please notice that, (x=5, y=7) and (x=7, y=5) are considered to be the same.Yoiu can assume that a = c = 1 in all test cases.
Input
The input consists of several test cases. The first line of the input is the number of the cases. There are no more than 3,000 cases. Each case contains five integers: a, b, c, d, k, 0 < a <= b <= 100,000, 0 < c <= d <= 100,000, 0 <= k <= 100,000, as described above.
Output
For each test case, print the number of choices. Use the format in the example.
Sample Input
2
1 3 1 5 1
1 11014 1 14409 9Sample Output
Case 1: 9
Case 2: 736427
题意:给出 A , B , C , D , k 五个数,设 x 属于 [A,B],y 属于[C,D] ,求有多少对(x,y)满足 GCD(x,y)=k,其中 A、C 一定为 1
思路:
由于 A、C 一定为 1,因此问题实质是求 的值
设 f(k) 为满足 GCD(i,j)=k 的个数,即:
g(k) 为满足 GCD(i,j)= k 的倍数的个数,即:
可以看出,其符合莫比乌斯反演的形式:
因此,可得:
由于计算区间是 [1,B']、[1,D'],计算的是 GCD(x,y)=1,也就是计算 f(1)
故有:
此时的 ans=f(1) 是所有的个数,但存在重复情况,利用容斥定理进行去重,故需要再统计 1~minn 中的所有 mu[i]*(minn/i)*(minn/i) 的个数 num,统计完成后,由于是两个区间,因此 num 需要除以 2,最终答案 res=ans-num/2
Source Program
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<bitset>
#define EPS 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define LL long long
#define Pair pair<int,int>
const int MOD = 1E9+7;
const int N = 100000+5;
const int dx[] = {1,-1,0,0,-1,-1,1,1};
const int dy[] = {0,0,-1,1,-1,1,-1,1};
using namespace std;
int mu[N];
int prime[N];
bool bprime[N];
int cnt;
void getMu(int n){//线性筛求莫比乌斯函数
cnt=0;
mu[1]=1;//根据定义,μ(1)=1
memset(bprime,false,sizeof(bprime));
for(int i=2;i<=n;i++){//求2~n的莫比乌斯函数
if(!bprime[i]){
prime[++cnt]=i;//存储质数
mu[i]=-1;//i为质数时,μ(1)=-1
}
for(int j=1;j<=cnt&&i*prime[j]<=n;j++){//枚举i之前的素数个数
bprime[i*prime[j]]=true;//不是质数
if(i%prime[j])//i不是prime[j]的整数倍时,i*prime[j]就不会包含相同质因子
mu[i*prime[j]]=-mu[i];//mu[k]=mu[i]*mu[prime[j]],因为prime[j]是质数,mu值为-1
else{
mu[i*prime[j]]=0;
break;//留到后面再筛
}
}
}
}
LL g[N];
int main(){
getMu(100000);
int t;
scanf("%d",&t);
int Case=1;
while(t--){
int a,b,c,d,k;
scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
if(k==0)
printf("Case %d: 0\n",Case++);
else{
int B=b/k,D=d/k;
int minn=min(B,D);
for(int i=1;i<=minn;i++)
g[i]=(LL)(B/i)*(D/i);
LL ans=0;//1~minn的总个数,存在重复计算
for(int i=1;i<=minn;i++)
ans+=(1LL)*mu[i]*g[i];
LL num=0;//1~minn中,重复计算的个数
for(int i=1;i<=minn;i++)
num+=(1LL)*mu[i]*(minn/i)*(minn/i);
LL res=ans-num/2;
printf("Case %d: %lld\n",Case++,res);
}
}
return 0;
}