題目:GCD hdu 1695
題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=1695
題意: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;給出abcdk五個數,求滿足GCD(x, y) = k的x,y的種數。其中x滿足在區間a...b內,y滿足在區間c...d內;
解題思路:GCD(x, y) = k可以進行轉換為GCD(x/k, y/k) = 1;在區間1...b/k與1...d/k內取小的那個求出在小一點的區間內互質的個數,再求在小區間內與大區間減去小區間的數中滿足條件的個數。利用尤拉與容斥來進行兩步的解決
AC程式碼:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define LL long long
#define maxn 100005
int x[maxn],cnt[1005];
int euler_phi(int n)
{
int m = (int)sqrt(n+0.5);
int ans = n;
for(int i = 2; i <= m; i++)
{
if(n%i==0)
{
ans = ans/i*(i-1);
while(n%i==0)
n/=i;
}
}
if(n>1)
ans = ans/n*(n-1);
return ans;
}
LL Imco_prime(int n,int m)
{
int i,j,t=0;
for(i=2; i*i<=n; i++)
{
if(n&&n%i==0)
{
cnt[t++]=i;
while(n&&n%i==0)
n/=i;
}
}
if(n>1)
cnt[t++]=n;
LL ans=0,tmp,flag;
for(i=1; i<(1<<t); i++)
{
tmp=1,flag=0;
for(j=0; j<t; j++)
if(i&(1<<j))
flag++,tmp*=cnt[j];
if(flag&1)
ans+=m/tmp;
else
ans-=m/tmp;
}
return ans;
}
int main()
{
int T,t=0,a,b,c,d,k,i;
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
if(k==0)
{
printf("Case %d: 0\n",++t);
continue;
}
b/=k,d/=k;
if(b>d)
swap(b,d);
LL ans=0,tmp=(LL)b*(d-b);
for(i=1; i<=b; i++)
ans+=euler_phi(i);
for(i=b+1; i<=d; i++)
tmp-=Imco_prime(i,b);
printf("Case %d: %I64d\n",++t,ans+tmp);
}
return 0;
}