zoukankan      html  css  js  c++  java
  • (Problem 72)Counting fractions

    Consider the fraction, n/d, where n and d are positive integers. If n<d and HCF(n,d)=1, it is called a reduced proper fraction.

    If we list the set of reduced proper fractions for d ≤ 8 in ascending order of size, we get:

    1/8, 1/7, 1/6, 1/5, 1/4, 2/7, 1/3, 3/8, 2/5, 3/7, 1/2, 4/7, 3/5, 5/8, 2/3, 5/7, 3/4, 4/5, 5/6, 6/7, 7/8

    It can be seen that there are 21 elements in this set.

    How many elements would be contained in the set of reduced proper fractions for d ≤ 1,000,000?

    题目大意:

    考虑分数 n/d, 其中n 和 d 是正整数。如果 n<d 并且最大公约数 HCF(n,d)=1, 它被称作一个最简真分数。

    如果我们将d ≤ 8的最简真分数按照大小的升序列出来,我们得到:

    1/8, 1/7, 1/6, 1/5, 1/4, 2/7, 1/3, 3/8, 2/5 , 3/7, 1/2, 4/7, 3/5, 5/8, 2/3, 5/7, 3/4, 4/5, 5/6, 6/7, 7/8

    可知该集合中共有21个元素。
    ≤ 1,000,000的最简真分数集合中包含多少个元素?

    算法一(超时):

    优化技巧:

    1、当分母n是素数,则以n为分母的最简真分数的数目为n-1

    2、当分母和分子奇偶不同的时候,进一步检查分母和分子的最大公约数

    #include<stdio.h>
    #include<stdbool.h>
    void swap(int* a, int* b)  //交换两值的函数
    {
        int t;
        t = *a;
        *a = *b;
        *b = t;
    } 
     
    int gcd(int a, int b)  //求最大公约数函数
    {
        int r;
        if(a < b) swap(&a, &b);
        while(b) {
            r = a % b;
            a = b;
            b = r;
        }
        return a;
    }
     
    bool prim(int n) //判断素数函数
    {
        int i;
        for(i = 2; i * i <= n; i++) {
            if(n % i == 0)  return false;
        }
        return true;
    }
     
    bool fun(int a, int b)  //判断两整数奇偶是否相同
    {
        return !((a & 1) & (b & 1));
    }
     
    void solve()
    {
        int i, j, t;
        long long count = 0;
        for(i = 2; i <= 100000; i++) {
            if(i % 2 && prim(i)) {
                count += i - 1;
                continue;
            }
            count++;
            for(j = 2; j < i; j++) {
                if(fun(i,j) && (i % j != 0)) {
                    t = gcd(i, j);
                    if(t == 1) count++;  //如果i,j互素,符合
                }
            }
        }
        printf("%lld
    ", count);
    }
     
    int main()
    {
        solve();
        return 0;
    }

    算法二:

    将1~1000000的整数分奇偶两部分计算,依然超时

    #include<stdio.h>
    #include<stdbool.h>
    
    #define N 1000000
     
    int gcd(int a, int b)  //求最大公约数函数
    {
        int r;
        while(b) {
            r = a % b;
            a = b;
            b = r;
        }
        return a;
    }
     
    bool prim(int n) //判断素数函数
    {
        int i;
        for(i = 2; i * i <= n; i++) {
            if(n % i == 0)  return false;
        }
        return true;
    }
     
    bool fun(int a, int b)  //判断两整数奇偶是否相同
    {
        return !((a & 1) & (b & 1));
    }
     
    void solve()
    {
        int i, j, t;
        long long count = 0;
        for(i = 2; i <= N; i += 2) {
            count++;
            for(j = 3; j < i; j += 2) { 
                t = gcd(i, j);
                if(t == 1) count++;
            }
            
        }
        for(i = 3; i < N; i += 2) {
            count++;
            if(prim(i)) {
                count += i - 1;
                continue;
            } else {
                for(j = 2; j < i; j++) {
                    if(gcd(i, j)) count++;
                }
            }
            
        }
        printf("%lld
    ", count);
    }
     
    int main()
    {
        solve();
        return 0;
    }

     算法三:

    #include<stdio.h>
    #include<stdbool.h>
    #include<math.h>
    
    #define N 1000001
    
    bool a[N];
    
    void Eratosthenes()
    {
        int i, M, j;
        for(i = 2; i < N; i++) {
            a[i] = true;
        }
        M = (int)sqrt(N);
        for(i = 2; i <= M; i++) { 
            if(a[i]) {
                j = i * i;
                for(; j < N; j += i)
                    a[j] = false;
            }
        }
    }
    
    int fun(int n)
    {
        int t, i, count, j;
        t = n / 2;
        i = 2;
        count = n - 1;
        while(i <= t) {
            if(a[i]) {
                if(n % i == 0) {
                    count--;
                    for(j = i; j * i < n; j++) {
                        count--;
                    }
                }
            }
            i++;
        }
        return count;
    }
      
    int main()
    {
        int i;
        long long count = 0;
        
        Eratosthenes();
    
        for(i = 2; i < N; i++) {
            if(a[i]) {
                count += i - 1;
            } else {
                count += fun(i);
            }
        }
        printf("%lld
    ", count);
        
        return 0;
    }

     算法四:使用欧拉函数

    //(Problem 72)Counting fractions
    // Completed on Tue, 18 Feb 2014, 14:08
    // Language: C11
    //
    // 版权所有(C)acutus   (mail: acutus@126.com) 
    // 博客地址:http://www.cnblogs.com/acutus/
    
    #include<stdio.h>
    #include<math.h>
    #include<stdlib.h>
    #include<stdbool.h>
    
    #define N 1000001
    
    int phi[N];     //数组中储存每个数的欧拉数
    
    void genPhi(int n)//求出比n小的每一个数的欧拉数(n-1的)
    {
        int i, j, pNum = 0 ;
        memset(phi, 0, sizeof(phi)) ;
        phi[1] = 1 ;
        for(i = 2; i < n; i++)
        {
            if(!phi[i])
            {
                for(j = i; j < n; j += i)
                {
                    if(!phi[j])
                        phi[j] = j;
                    phi[j] = phi[j] / i * (i - 1);
                }
            }
        }
    }
    
    void solve()
    {
        int i;
        long long ans =0;
        for(i = 2; i < N; i++) {
            ans += phi[i];
        }
        printf("%lld
    ", ans);
    }
    
    int main()
    {
        genPhi(N);
        solve();
        return 0;
    }
    Answer:
    303963552391
  • 相关阅读:
    VS2008下编的程序生成的EXE 在没有安装VS2008的计算机上能运行
    GDI+使用小记
    双缓冲技术绘图
    INI文件格式及其读写
    缩放图片并保存
    按值传递&&按引用传递&&按地址传递
    傻瓜式制作的U盘winpe(支持4G以上U盘)速度超快
    vi 命令大全
    fopen和open的区别
    Linux下Socket网络编程,文件传输,数据传输的C语言例子
  • 原文地址:https://www.cnblogs.com/acutus/p/3550597.html
Copyright © 2011-2022 走看看