zoukankan      html  css  js  c++  java
  • HDU 1695 GCD 欧拉函数+容斥定理 || 莫比乌斯反演

    GCD

    Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 4141    Accepted Submission(s): 1441


    Problem Description
    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. GCD(x, y) means the greatest common divisor of x and y. Since the number of choices may be very large, you're only required to output the total number of different number pairs.
    Please notice that, (x=5, y=7) and (x=7, y=5) are considered to be the same.

    Yoiu can assume that a = c = 1 in all test cases.
     
    Input
    The input consists of several test cases. The first line of the input is the number of the cases. There are no more than 3,000 cases.
    Each case contains five integers: a, b, c, d, k, 0 < a <= b <= 100,000, 0 < c <= d <= 100,000, 0 <= k <= 100,000, as described above.
     
    Output
    For each test case, print the number of choices. Use the format in the example.
     
    Sample Input
    2
    1 3 1 5 1
    1 11014 1 14409 9
    Sample Output
    Case 1: 9
    Case 2: 736427
      1 /*
      2 题意:区间x属于[1,A] , y属于区间[1,B]
      3       求最大公约数是K,即gcd(x,y)=K。
      4       并且[1,3]和[3,1]属于同一种情况。
      5       
      6 思路:HDU 4135 Co-prime 的思路在这一题有用。
      7       它的题意:区间[A,B],与整数N的互素的个数
      8       对于这一到题目:gcd(x,y)=k.
      9       要满足最大公约数是K,可以转化为
     10       [1,A],[1,B]==>[1,A/K],[1,B/K] 求互素的个数。
     11       好像有点难以想到。????
     12       {{
     13       借鉴一下别人是说法。会更明白
     14       gcd(x, y) == k 说明x,y都能被k整除,但是能被k整除的未必gcd=k , 
     15       必须还要满足互质关系. 
     16       问题就转化为了求1~a/k 和 1~b/k间互质对数的问题
     17       }}
     18       这样的话,如何处理呢?
     19       题意要求[1,3]和[3,1]不能重复。
     20       对于区间[1,A/K],[1,B/K] 看成==>[1,a],[1,b] 有几种情况
     21       1____________a
     22       1____________________b
     23       
     24       
     25       1____________a
     26       1________b
     27       
     28       
     29       1____________a
     30       1____________b
     31       
     32       这三种情况。我们来个判断,总是让a<=b,用b做更大的值。就会变成
     33       
     34       1—————————a
     35       1—————————————————b
     36       在求取的过程中也是采取这样的规则。
     37       [?,b1];确定后一位数。表示在[1,a]中与b1互质的个数。
     38       那么就很好的避免了[1,3],[3,1]的情况了。
     39 求取总和sum=sum1+sum2;
     40 sum1=欧拉函数值[1,a]; 想想为什么?
     41 sum2={枚举a+1--->b,与区间[1,a]互质的个数}; 
     42 sum2就和以前的一题有关系了,要用欧拉函数+容斥定理处理。
     43 具体的参考:http://www.cnblogs.com/tom987690183/p/3246197.html
     44 
     45 
     46 */
     47 
     48 #include<stdio.h>
     49 #include<string.h>
     50 #include<stdlib.h>
     51 
     52 
     53 int prime[100003],len;
     54 bool s[100003];
     55 int opl[100003];
     56 int Que[100003];
     57 int f[1000],flen;
     58 
     59 void make_prime() //素数打表
     60 {
     61     int i,j;
     62     len=0;
     63     for(i=2;i<=100000;i++)//刚开始写错,i*i<=100000;⊙﹏⊙b汗
     64     if(s[i]==false)
     65     {
     66         prime[++len]=i;
     67         for(j=i*2;j<=100000;j=j+i)
     68         s[j]=true;
     69     }
     70 }
     71 
     72 void make_Euler() //欧拉函数打表。
     73 {
     74     int i,j;
     75     make_prime();
     76     for(i=2;i<=100000;i++)
     77     opl[i]=i;
     78     opl[1]=1;
     79     for(i=1;i<=len;i++)
     80     for(j=prime[i];j<=100000;j=j+prime[i])
     81     opl[j]=opl[j]/prime[i]*(prime[i]-1);
     82 }
     83 
     84 void make_dEuler(int n) //单点欧拉的素因子。
     85 {
     86     int i;
     87     flen=0;
     88     for(i=2;i*i<=n;i++)
     89     {
     90         if(n%i==0)
     91         {
     92             while(n%i==0)
     93             n=n/i;
     94             f[++flen]=i;
     95         }
     96     }
     97     if(n!=1)
     98     f[++flen]=n;
     99 }
    100 
    101 int Capacity(int m)
    102 {
    103     int i,j,t=0,sum=0,k;
    104     Que[t++]=-1;
    105     for(i=1;i<=flen;i++)
    106     {
    107         k=t;
    108         for(j=0;j<k;j++)
    109         Que[t++]=-1*Que[j]*f[i];
    110     }
    111     for(i=1;i<t;i++)
    112     sum=sum+m/Que[i];
    113     return sum;
    114 }
    115 
    116 
    117 void sc()//输出函数,测试用的。
    118 {
    119     int i;
    120     for(i=1;i<=10;i++)
    121     printf("%d ",opl[i]);
    122     printf("
    ");
    123 }
    124 
    125 __int64 make_ini(int b,int c,int k)
    126 {
    127     int i,x,y,tmp;
    128     __int64 sum=0;
    129     x=b/k;y=c/k;//加特判的用处。不能除0
    130     if(x>y)
    131     {
    132         tmp=x;
    133         x=y;
    134         y=tmp;
    135     }
    136     for(i=1;i<=x;i++)
    137     sum=sum+opl[i];//第一步
    138     for(i=x+1;i<=y;i++)//第二步,枚举
    139     {
    140         make_dEuler(i);
    141         sum=sum+(x-Capacity(x));
    142     }
    143     //sc();
    144     return sum;
    145 
    146 }
    147 
    148 int main()
    149 {
    150     int T,a,b,c,d,k,i;
    151     __int64 sum;
    152     make_Euler();
    153     while(scanf("%d",&T)>0)
    154     {
    155         for(i=1;i<=T;i++)
    156         {
    157             sum=0;
    158             scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
    159             if(k==0) //特判,否则会Runtime Error (INTEGER_DIVIDE_BY_ZERO)
    160             {
    161                 sum=0;
    162             }
    163             else sum=make_ini(b,d,k);
    164             printf("Case %d: %I64d
    ",i,sum);
    165 
    166         }
    167     }
    168     return 0;
    169 }
    下面再介绍一种方法。莫比乌斯反演
    GCD(a,b) = d;
    可以转化为
    GCD(a/d,b/d) = 1;
    设f(d)为(a,b) = d的种类数
       F(d)为(a,b) = d 的倍数 的种类数。
    例如
    F(2) = (a/2)*(b/2);
    F(3) = (a/3)*(b/3);
    mu[i]可以打表求出。
    关于一个优化在于a/i = a/(i+k) && b/i = b/(i+k);
    此时我们能节省时间来求。详见代码部分
     1 #include<iostream>
     2 #include<stdio.h>
     3 #include<cstring>
     4 #include<cstdlib>
     5 using namespace std;
     6 typedef __int64 LL;
     7 
     8 const int maxn = 1e5+3;
     9 bool s[maxn];
    10 int prime[maxn],len = 0;
    11 int mu[maxn];
    12 int sum1[maxn];
    13 void  init()
    14 {
    15     memset(s,true,sizeof(s));
    16     mu[1] = 1;
    17     for(int i=2;i<maxn;i++)
    18     {
    19         if(s[i] == true)
    20         {
    21             prime[++len]  = i;
    22             mu[i] = -1;
    23         }
    24         for(int j=1;j<=len && (long long)prime[j]*i<maxn;j++)
    25         {
    26             s[i*prime[j]] = false;
    27             if(i%prime[j]!=0)
    28                 mu[i*prime[j]] = -mu[i];
    29             else
    30             {
    31                 mu[i*prime[j]] = 0;
    32                 break;
    33             }
    34         }
    35     }
    36     for(int i=1;i<maxn;i++)
    37         sum1[i] = sum1[i-1]+mu[i];
    38 }
    39 LL solve(int a,int b)
    40 {
    41     LL sum = 0;
    42     for(int i=1,la = 0;i<=a;i++,i = la+1)
    43     {
    44         la = min(a/(a/i),b/(b/i)); //优化部分
    45         sum = sum + ((LL)(a/i))*(b/i)*(sum1[la]-sum1[i-1]);
    46     }
    47     return sum;
    48 }
    49 int main()
    50 {
    51     int T,l,a,b,d;
    52     init();
    53     scanf("%d",&T);
    54     for(int t=1;t<=T;t++)
    55     {
    56         scanf("%d%d%d%d%d",&l,&a,&l,&b,&d);
    57         LL sum = 0 ;
    58         if(d==0) ;
    59         else{
    60             if(a>b) swap(a,b);
    61             sum = solve(a/d,b/d);
    62             sum = sum - solve(a/d,a/d)/2;
    63         }
    64         printf("Case %d: %I64d
    ",t,sum);
    65     }
    66     return 0;
    67 }
     
  • 相关阅读:
    Bit Calculation
    Create ArcGIS maps in Power BI Desktop
    Power Apps visual for Power BI
    Create Power BI visuals by using Python
    运行 R 脚本
    Introduction to ASP.NET Core Blazor
    Tips and tricks for color formatting in Power BI
    Sharepoint Create, Update, and Delete List Items
    Power BI Office Online Server
    jQuery Organization Chart
  • 原文地址:https://www.cnblogs.com/tom987690183/p/3246504.html
Copyright © 2011-2022 走看看