1. 程式人生 > 實用技巧 >Orac and LCM CodeForces - 1349A

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;
}

其實建議第一種方法。