Orac and LCM CodeForces - 1349A

Orac and LCM

 CodeForces - 1349A 

方法一:

先说结论:

  • gcd(a, lcm(b, c)) = lcm(gcd(a, b), gcd(a, c))
  • lcm(a, gcd(b, c)) = gcd(lcm(a, b), lcm(a, c))

这就是传说中的分配律嘛,爱了爱了。我们知道答案就是要求__gcd(lcm(a1,a2), lcm(a1,a3)......,lcm(a2,a3), lcm(a2,a4)......lcm(an-1,an)),所以我们不妨把其分解成__gcd(__gcd(lcm(a1,a2), lcm(a1,a3)......), __gcd(lcm(a2,a3), lcm(a2, a4),.......)。

对于__gcd(lcm(a1, a2), lcm(a1, a3), ......)由结论可推导原式等于__gcd(a1, lcm(a2, a3, ......an))

对于__gcd(lcm(a2, a3), lcm(a2, a4), ......)由结论可推导原式等于__gcd(a2, lcm(a3, a4, ......an))

故答案为:__gcd(__gcd(a1, lcm(a2, a3, ......an)), __gcd(a2, lcm(a3, a4, ......an)), ...... __gcd(an-1, lcm(an))

我们可以通过一个后缀数组进行求解lcm。

代码见:https://blog.csdn.net/weixin_44116061/article/details/106348618

方法二:

题解中说,若要满足某个质数p的k次方对于最后答案有影响,那么其一定是至少在数组有n-1个a分解成质数后均含有p才能,试想,如果n-1个都含有p,那么任意的lcm都会含有一个含有p的a,那么所有的lcm结果均包含p,最终的结果也会包含p的k次方(其中k为n-1个a里面最小的指数幂,因为要求最大公约数,必定是取最小的因为取最小所有的都满足整除p的k次)。如果全含有p,那么也是一样的,只不过这里是要第二小(我们知道lcm(p^1, p^2)肯定是p^2,所以所有的lcm结果都是两个中p的指数大的那个,然后再取这些的最小,那么最小的指数在lcm中就被淘汰了,在剩下的选最小的k只能是第二小的了)。对于某个数,如果我们忽略掉,那么剩余数的gcd就是n-1个a分解后均含有的p的k乘积(p1^k1*p2^k2......),但是不同数忽略之后的gcd可能有p是相同的,那么我们要取唯一的p,那么我们采用对于每个gcd求所有的gcd的lcm即可。对于去掉某个a求剩余的gcd,我们可以采用分别求前缀的gcd和后缀的gcd再一次gcd得到。

可行性简单描述:

因为对于所有的质数p,如果它是在n-1个中出现,那么它必定在某个a被去掉的gcd中出现;如果在n个中均出现,对于求所有的gcd的lcm而言,在含有p的最小k的a被去掉后剩余的gcd中是包含了p的第二小的k的幂的,其余的情况因为p的最小的k没被去掉,所以剩余的gcd中包含的都是p的最小k的幂,lcm的时候对于p是取到的是第二小的,证明见上面证明lcm(p^1, p^2)结果是p^2的那里。而我们知道如果在n个中出现,正确的结果就是p的第二小的幂;对于在小于n-1个中出现的,在去掉任意一个元素所求的gcd中均不会出现该元素。综上,采用对于分别去掉某个a对于剩下的采用gcd,然后对所有的gcd进行lcm的结果是正确的。

AC代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll ;
const int maxn = 100005;
ll pre[maxn];
ll suf[maxn];
ll a[maxn];
ll ans;
int main()
{
    int n;
    scanf("%d", &n);
    for(int i = 0; i < n; i++)
        scanf("%lld", &a[i]);
    pre[0] = a[0], suf[n - 1] = a[n - 1];
    for(int i = 1; i < n; i++)
    {
        pre[i] = __gcd(pre[i - 1], a[i]);
    }
    for(int i = n - 2; i >= 0; i--)
    {
        suf[i] = __gcd(suf[i + 1], a[i]);
    }
    for(int i = 0; i < n; i++)
    {
        if(i == 0)
            ans = suf[1];
        else if(i == n - 1)
            ans = ans / __gcd(ans, pre[n - 2]) * pre[n - 2];
        else
            ans = ans / __gcd(ans, __gcd(pre[i - 1], suf[i + 1])) * __gcd(pre[i - 1], suf[i + 1]);
    }
    printf("%lld\n", ans);
    return 0;
}

 

其实建议第一种方法。

 

 

posted @ 2020-07-28 17:43  funforever  阅读(168)  评论(0编辑  收藏  举报