需要提高运行时间的复杂性吗?

时间:2018-08-09 22:34:55

标签: c++

#include<iostream>
using namespace std;
int gcd(int a, int b, int res);
int main()
{
    int res = 1;
    int n, i, ret;
    int count = 1;
    cin >> n;
    for (i = 2; i < n; i++)
    {
        ret = gcd(n, i, res);
        if (ret == 1)
            count++;
    }
    cout << count;
    return 0;
}
int gcd(int a, int b, int res)
{
    if (a == b)
        return res * a;
    else if ((a % 2 == 0) && (b % 2 == 0))
        return gcd(a / 2, b / 2, 2 * res);
    else if (a % 2 == 0)
        return gcd(a / 2, b, res);
    else if (b % 2 == 0)
        return gcd(a, b / 2, res);
    else if (a > b)
        return gcd(a - b, b, res);
    else
        return gcd(a, b - a, res);
}

请说明我需要更正的内容,例如可以使用scanf代替cin? 还有一个条件是:-输入的唯一行是单个整数N,该整数N可以被大于13的素数整除。该条件会影响我的TLE吗?

实际问题是:

逆 问题描述 每个人都知道乘法mod n,其中n是一个正整数。当乘积除以n时,两个正整数a和b mod n的乘积就是余数。

如果存在一个小于n的正整数x,那么a就相对于n具有一个乘法逆。因此,a与x mod n的乘积为1。

伟大的数学家欧拉(Euler)证明,每个小于n的正整数(以n为素数(除1之外没有与n相同的公因数))相对于n都有一个乘法逆。

这个问题是要找到小于n的正整数的数量,该数量相对于n具有可逆的乘法

约束 N <10 ^ 9

输入格式 输入的唯一行是单个整数N,该整数N可以被任何不大于13的质数整除。

输出 一行包含一个整数,该整数给出小于N且具有可乘逆数的整数

说明 示例1

输入

20

输出

8

说明

N = 20

如果我们列出小于20且与1以外的20没有公因数的数字,则为

1、3、7、9、11、13、17、19

因为它们有8个,所以有少于20个的8个数字相对于20具有一个乘法逆。因此结果为8。

示例2

输入

36

输出

12

说明

N = 36。小于36的数字有12个,除1与36之外没有其他公因数。

1、5、7、11、13、17、19、23、25、29、31、35

因此,正如欧拉所证明的那样,小于36的数字有12个,相对于36具有一个乘法逆。因此,输出为12。 https://i.stack.imgur.com/cvM0l.png

1 个答案:

答案 0 :(得分:1)

首先,为什么自C ++ 17起<numeric>中包含std::gcd,为什么要实现自己的gcd。您的GCD实现具有相同的O(log N)复杂度,但是由于大量条件而效率很低:

对于N = 100000000(亿),您的算法在我的计算机上运行26秒。使用std::gcd()可以运行15秒。这是更好的,但不是很多。

如果您没有C ++ 17,则:

int gcd(int a, int b)
{
    if (b < a)
        std::swap(a, b);
    while (a != 0) {
        b %= a;
        std::swap(a, b);
    }
    return b;
}

具有与std::gcd()相同的性能。

但是那仍然太慢了。更好的方法是进行分析工作。 您要计算[1..N]范围内与N没有公因数的整数数。这很简单,无需实际枚举所有值。首先,找到N的所有素数。

让我们说N=a^m * b^n * c^k(对于m,n,k> = 1)。 范围内有N * (a-1) / a个没有a作为因子的值。其中有N * (a-1) / a * (b-1) / b个没有b作为因素,依此类推。这仅是因为a,b,c是质数,它们也是N的因数。否则,除法将不准确或不是整数。

这使代码快速运行:

#include<iostream>
int main()
{
    unsigned n;
    std::cin >> n;
    if (!std::cin) {
        std::cout << "Bad input\n";
        return 1;
    }
    unsigned count = n;
    unsigned factors_left = n;
    // i is long long to avoid overflow for i * i, 
    // where n is a big prime
    for (unsigned long long i=2 ; i * i <= factors_left ; ++i) {
        if (factors_left % i == 0) {
            while (factors_left % i == 0)
                factors_left /= i;
            count -= count / i;
        }
    }
    if (factors_left > 1)
        // factors_left is a prime number
        count -= count / factors_left;

    std::cout << count << "\n";
    return 0;
}

复杂度= O(sqrt(n))。最坏的情况是n为素数或素数的平方。这比原始的O(n log n)好得多。返回结果N = 100000000只需一秒钟。

edit:如果考虑到附加条件,则最大质数为13,则for循环可以迭代到13。在这种情况下,复杂度变为O(log N),因为这是内部函数的复杂度循环。