CF-Round #641-div2-C题&div1A题
C. Orac and LCM
这道题是关于lcm和gcd的题目~
题目大意:让你求所给数组中所有两两数字的最小公倍数的最大公约数。
本题思路:
我们要求这些数字的最小公倍数的最大公约数。
比如我们求数组a[] = {x, y, z};这三个数的两两数字间的最小公倍数的最大公约数。
我们先来解决关于每个数的最小公倍数的最大公约数。(最后我们只用求这些数的最大公约数即可)
关于x的最小公倍数:gcd(x * y / gcd(x, y), x * z / gcd(x, z));
提取出x。
x * gcd(y / gcd(x, y), z / gcd(x. z));
对于gcd(y / gcd(x, y), z / gcd(x. z))
我们把这个式子的y, z提取出来;
变成了:
gcd(y, z) / gcd(gcd(x, y), gcd(x, z));
进一步化简:
gcd(y, z) / gcd(x, y, z);
相当于我们求把gcd(y / gcd(x, y), z / gcd(x. z))转化为gcd(y, z)时扩大了gcd(gcd(x, y), gcd(x, z))倍。
然后我们观察gcd(y, z) / gcd(x, y, z);
可以发现,维护一下后缀gcd就可以啦~
然后我们后面就可以直接以此类推啦~
我们从后往前向后计算。
先计算最后一个数的最小公倍数的最大公约数。最后一个数的gcd就是自己本身嘛(向后计算,这样的顺序可以保证全部都计算到)
然后往前走,更新ans即可。
suf[]数组是计算后缀的gcd的~
代码部分:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
typedef long long ll;
ll a[N];
ll suf[N];
ll gcd(ll a, ll b)
{
if (!b)
{
return a;
}
return gcd(b, a % b);
}
int main()
{
int n;
scanf ("%d", &n);
for (int i = 1; i <= n; i++)
{
scanf ("%I64d", &a[i]);
}
suf[n] = a[n];
for (int i = n - 1; i >= 1; i--)
{
suf[i] = gcd(suf[i + 1], a[i]);
}
ll ans = 1ll * a[n] * a[n - 1] / suf[n - 1];
for (int i = n - 2; i >= 1; i--)
{
ans = 1ll * gcd(ans, a[i] * suf[i + 1] / suf[i]);
}
cout << ans << endl;
return 0;
}