#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
答案 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),因为这是内部函数的复杂度循环。