题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1695
题目大意:求(1,b)区间和(1,d)区间里面gcd(x, y) = k的数的对数(1<=x<=b , 1<= y <= d)。
思路:让x,y都除上k,就是求gcd(x,y)=1的对数,gcd=1就是两个数互质,那么问题就可以转换成在(1,b/k)和(1,d/k)中互质的数的对数,题意告诉(1,3)和(3,1)为一种情况,所以限制x<=y即可;
要预处理求出所有数的素因数;
答案很大,用long long 记录答案;
#include<stdio.h>
#include<string.h>
#include<string>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<set>
#include<algorithm>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int N=1e5+4;
vector<int>prime[N];
int vis[N];
void get_prime()//得到所有数的素因数
{
memset(vis,0,sizeof(vis));
for(int i=0;i<N-1;++i)
prime[i].clear();
for(int i=2;i<N-1;i+=2)
prime[i].push_back(2);
for(int i=3;i<N-1;i+=2)
{
if(!vis[i])
{
for(int j=i;j<N-1;j+=i)
{
vis[j]=1;
prime[j].push_back(i);
}
}
}
}
int solve(int n,int m)
{
int sum=0;
for(int i=1; i<(1<<prime[m].size()); ++i)
{
int k=0,pa=1;
for(int j=0; j<prime[m].size(); ++j)
{
if(i&(1<<j))
{
k++;
pa*=prime[m][j];
}
}
int cur=n/pa;
if(k&1) sum+=cur;
else sum-=cur;
}
return sum;
}
int main()
{
get_prime();
int a,b,c,d,k;
int T,cas=0;
scanf("%d",&T);
while(T--)
{
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);
ll ans=0;
for(int i=1; i<=d; i++)
{
int t=min(i,b);//如果此时i<b,就是求区间[1,i]中与i互质的数,
ans+=t; //否则就是求区间[1,b]中与i互质的数,因为是为了时x<=y;
ans-=solve(t,i);//1~t之间与i互素的数的个数
}
printf("Case %d: %lld\n",++cas,ans);
}
return 0;
}