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 }


  • 相关阅读:
    Lucene.Net 2.3.1开发介绍 —— 二、分词(一)
    控制‘控制台应用程序’的关闭操作
    详解for循环(各种用法)
    敏捷软件开发
    Sql Server的一些知识点
    在SharePoint 2010 中配置Remote Blob Storage FILESTREAM Provider
    使用LotusScript操作Lotus Notes RTF域
    JOpt Simple 4.5 发布,命令行解析器
    John the Ripper 1.8.0 发布,密码破解工具
    PacketFence ZEN 4.0.1 发布,网络接入控制
  • 原文地址:https://www.cnblogs.com/acSzz/p/2785499.html
Copyright © 2011-2022 走看看