题意: 在区间[a,b]中选择一个数,在区间[c,d]中选择一个数 问这两个数的gcd值为k有多少个
分析:我们找gcd为k的数并不好找,但找gcd为1的数就好找的多我们把b/=k,d/=k就变成在区间内找gcd值为1的个数了,此外我们注意到本题可以假设a c为1 所以区间就是[1,b] [1,d] 我们可以分成区间[1,b] 和区间[b+1,b]两部分 在前一部分只需要求出没个数的欧拉函数值累加起来即可,后一个区间中找出一个数与前一个区间中的数互质即可,我们利用容斥原理,
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <math.h>
#include <vector>
#include <string>
#include <utility>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
struct sa{
int k;
int fec[20];
}p[100005];
long long phi[100005];
void euler(){
phi[1]=1;
for(int i=1;i<100005;i++)
p[i].k=0;
for(int i=2;i<100005;i++){
if(!phi[i]){
for(int j=i;j<100005;j+=i){
if(!phi[j])phi[j]=j;
phi[j]=phi[j]*(i-1)/i;
p[j].fec[p[j].k]=i;
p[j].k++;
}
}
phi[i]+=phi[i-1];
}
}//利用递推公式一边求欧拉函数,一边把每个数质因子分解
long long solve(int id,int b,int n){
long long sum=0,t;
for(int i=id;i<p[n].k;i++){
t=b/p[n].fec[i];
sum+=t-solve(i+1,t,n);
}
return sum;
}//递归实现容斥原理
int main(){
euler();
int m=1;
int a,b,c,d,k;
int t;
scanf("%d",&t);
while(t--){
scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
if(k==0){
printf("Case %d: 0\n",m++);
continue;
}
b/=k;
d/=k;
if(b>d)swap(b,d);//交换两个数,使得b<d
long long sum=phi[b];
for(int i=b+1;i<=d;i++){
sum+=b-solve(0,b,i);
}
printf("Case %d: %I64d\n",m++,sum);
}
return 0;
}
先将x进行质因子分解,然后,在[1,b]中找到能被x质因子整除的个数,用b-减去这个数就行了。