zoukankan      html  css  js  c++  java
  • 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 }


  • 相关阅读:
    线程TLAB区域的深入剖析
    ivotal-tc-Server与Tomcat区别
    Java线程面试题 Top 50 (转载)
    Java并发编程:Timer和TimerTask(转载)
    Java并发编程:Callable、Future和FutureTask
    Java并发编程:CountDownLatch、CyclicBarrier和Semaphore
    Java并发编程:线程池的使用
    Java多线程与并发库高级应用-可阻塞的队列
    java多线程与并发库高级应用-工具类介绍
    Google guava工具类的介绍和使用
  • 原文地址:https://www.cnblogs.com/acSzz/p/2785499.html
Copyright © 2011-2022 走看看