题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1695
求[1,b]区间和[1,d]区间里面gcd(x,y) = k的数的对数(1<=x<=b , 1<= y <= d)
b和d分别除以k之后的区间里面,只需要求gcd(x, y) = 1就可以了,这样子求出的数的对
这道题目还要求1-3 和 3-1 这种情况算成一种,因此只需要限制x<y就可以了
只需要枚举x,然后确定另一个区间里面有多少个y就可以了。因此问题转化成为区间[1,d]里面与x互素的数的个数
具体求互素个数方法见:http://blog.youkuaiyun.com/f_xuan/article/details/44835193
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
using namespace std;
#define MAX(a,b) ((a>b)?(a):(b))
#define MIN(a,b) ((a<b)?(a):(b))
#define INF 1<<30
#define N 100005
#define LL long long
vector<LL> p[N];
int vis[N];
void init(){
memset(vis,0,sizeof(vis));
for(int i=2;i<=N;++i){
if(!vis[i]){
for(int j=i;j<=N;j+=i){
vis[j]=1;
p[j].push_back(i);
}
}
}
}
LL cal(LL n,LL r)//[1,r]中与n互质的个数
{
/*
vector<LL> p;
for(LL i=2;i*i<=n;++i){
if(n%i==0){
p.push_back(i);
while(n%i==0)n/=i;
}
}
if(n>1)
p.push_back(n);
*/
LL ans=0;
for(LL i=1;i<(1<<p[n].size());++i){
LL multi=1,cnt=0;
for(LL j=0;j<p[n].size();++j){
if(i&(1<<j)){
cnt++;
multi*=p[n][j];
}
}
LL cur=r/multi;
if(cnt&1) ans+=cur;
else ans-=cur;
}
return r-ans;
}
int main(){
init();
int t,cas=1;
scanf("%d",&t);
while(t--){
LL ans=0;
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",cas++);
continue;
}
b/=k,d/=k;
if(b>d) swap(b,d);
for(int i=1;i<=d;++i){
int r=MIN(i,b);
ans+=cal(i,r);
}
printf("Case %d: %I64d\n",cas++,ans);
}
return 0;
}