hdu 1695 GCD (素数筛选 + 欧拉函数 + 容斥原理)

http://acm.hdu.edu.cn/showproblem.php?pid=1695

题意:求 1~b  和 1~ d  有 多少对 数 的 gcd(x,y) = k ?

       x = 5  y=7 和 x= 7,y = 5 被认为是 同一种。

题解:

如果两个数的 最大 公约数  是  k 的 话 ,那么  x/k  与  y /k  是 互质的。

所以 原题 可以转化为  求  1~b/k   和 1~d/k  有 多少对 互质的 数。

 

假设 b = b/k,d= d/k ,b<d

1:对于  1~b 我们可以 利用 欧拉函数 求 其 欧拉函数值 。

 

欧拉函数是指:对于一个正整数n,小于n且和n互质的正整数的个数,记做:φ(n),其中φ(1)被定义为1,但是并没有任何实质的意义

定义小于n且和n互质的数构成的集合为Zn,称呼这个集合为n的完全余数集合。

显然,对于素数p,φ(p)= p -1.对于两个素数p、q,他们的乘积n = pq 满足φ(n) =(p-1)(q-1)

         证明:对于质数p,q,满足φ(n) =(p-1)(q-1)
         考虑n的完全余数集Zn = { 1,2,....,pq -1}
         而不和n互质的集合由下面三个集合的并构成:
         1) 能够被p整除的集合{p,2p,3p,....,(q-1)p} 共计q-1个
         2) 能够被q整除的集合{q,2q,3q,....,(p-1)q} 共计p-1个
         3) {0}
         很显然,1、2集合中没有共同的元素,因此Zn中元素个数 = pq - (p-1 + q- 1 + 1) = (p-1)(q-1)

         上式中黑体的1是它本身,因为是小于它且和它互质的数,所以当然必须减去自身了。

欧拉函数的定义:E(k)=([1,n-1]中与n互质的整数个数).因为任意正整数都可以唯一表示成如下形式:
k=p1^a1*p2^a2*……*pi^ai;(即分解质因数形式)
可以推出:E(k)=(p1-1)(p2-1)……(pi-1)*(p1^(a1-1))(p2^(a2-1))……(pi^(ai-1))
               =k*(p1-1)(p2-1)……(pi-1)/(p1*p2*……pi);
               =k*(1-1/p1)*(1-1/p2)....(1-1/pk)

/*在程序中利用欧拉函数如下性质,可以快速求出欧拉函数的值(a为N的质因素)
若(N%a==0 && (N/a)%a==0) 则有:E(N)=E(N/a)*a;
若(N%a==0 && (N/a)%a!=0) 则有:E(N)=E(N/a)*(a-1);

*/

 2:  对于  大于 b 的 我门可以 利用  容斥原理 求出 。

 

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<cmath>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include< set>
  7 #include<map>
  8 #include<queue>
  9 #include<vector>
 10 #include< string>
 11  #define inf 0x7fffffff
 12  #define maxn 160000
 13  #define CL(a,b) memset(a,b,sizeof(a))
 14  #define  ll  long long
 15  #define mx 100010
 16  using  namespace std;
 17 
 18 
 19  bool f[maxn] ;
 20 ll phi[maxn] ; // 记录欧拉函数值
 21  ll prim[maxn] ;
 22 vector<ll>g[maxn];
 23  void init() //  素数筛选 及求 欧拉函数值
 24  {
 25     ll num =  0 ,i,j;
 26 
 27     phi[ 1] =  1 ;
 28 
 29     CL(f, false) ;
 30 
 31      for(i =  2 ; i <=  100000;i++)
 32     {
 33 
 34          if(f[i] ==  false)
 35         {
 36             prim[num++] = i;
 37             phi[i] = i -  1 ;
 38         }
 39          for(j =  0;j< num&&prim[j]*i <=  100000;j++)
 40         {
 41               f[i*prim[j]] =  true ;
 42                if(i%prim[j] ==  0)
 43               {
 44                   phi[i*prim[j]] = phi[i] *prim[j] ;
 45 
 46               }
 47                else
 48                  phi[i*prim[j]] = phi[i]*(prim[j] -  1) ;
 49 
 50         }
 51     }
 52 
 53 
 54 
 55      for(ll x =  1 ; x <=  100000;x++) // 找出所有数的 质因子
 56      {
 57 
 58         ll tmp = x;
 59         for(i =  0 ;prim[i] *prim[i] <= tmp ;i++)
 60        {
 61             if(tmp % prim[i] ==  0)
 62            {
 63                g[x].push_back(prim[i]) ;
 64 
 65                 while(tmp%prim[i] ==  0)tmp/=prim[i] ;
 66            }
 67 
 68 
 69             if(tmp ==  1break ;
 70        }
 71 
 72        if(tmp >  1)g[x].push_back(tmp) ;
 73     }
 74 }
 75 
 76 
 77 ll dfs(ll x,ll b,ll now) // 容斥原理
 78  {
 79     ll  res  =  0  ;
 80     ll i =  0 ;
 81      for(i = x; i < g[now].size();i++ )
 82        res = res + b/g[now][i] - dfs(i+ 1,b/g[now][i],now) ;
 83 
 84     return res ;
 85 }
 86  int main()
 87 {
 88      int T ,i;
 89     init() ;
 90     scanf( " %d ",&T);
 91      int cas =  0 ;
 92     ll a,b,c,d ,k;
 93      while(T--)
 94     {
 95         scanf( " %I64d%I64d%I64d%I64d%I64d ",&a,&b,&c,&d,&k) ;
 96 
 97          if(b > d ) swap(b,d) ;
 98 
 99          if(k ==  0|| k>b||k>d)
100         {
101             printf( " Case %d: 0\n ",++cas);
102              continue ;
103         }
104 
105         b = b/k ;
106         d = d/k  ;
107         ll ans =  0 ;
108          for(i =  1; i <= b;i++)
109            ans+=phi[i] ;
110          for(i = b+ 1; i <= d;i++)
111         {
112 
113             ans=ans + b - dfs( 0,b,i);
114 
115         }
116 
117 
118         printf( " Case %d: %I64d\n ",++cas,ans) ;
119 
120 
121 
122     }
123 
124 }

 


 

 

你可能感兴趣的:(HDU)