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 }


原文地址:https://www.cnblogs.com/acSzz/p/2785499.html