Codeforces Round 973题解(E)

E. Prefix GCD

假设我们从一个空集合b开始,不断从a数组中选择一个元素添加到b集合的尾部,当把a数组的元素全部添加到b中后,得到的b即为所求的rearrange后的a

结论1:

每次选择使得其和当前b中所有元素的最大公约数最小的那个ai加入到b的末尾,即选择ai,使得gcd(b1,b2,...,bk,ai)最小(假设当前b的大小为k),这样得到的b是最优的。

证明1:

假设当前的b集合为:
b1,b2,...,bk,此b集合即为正确答案的b的前k个元素。
使得gcd(b1,b2,...,bk,ai)取得最小值的a_i是A
而正确方案中这个步骤应该选择的aiB。那么有gcd(b1,b2,...,bk,A)<=gcd(b1,b2,...,bk,B)

结论2:

可以把正确方案的b={b1,b2,...,bk,B}
替换成:
b={b1,b2,...,bk,A,B},这样结果不会变坏。②

证明2:

f=gcd(a1)+gcd(a1,a2)++gcd(a1,a2,,an)
则①的fgcd(b1)+gcd(b1,b2)+...+gcd(b1,b2,...,bk)+gcd(b1,b2,...,bk,B)
②的fgcd(b1)+gcd(b1,b2)+...,+gcd(b1,b2,...,bk)+gcd(b1,b2,...,bk,A)+gcd(b1,b2,...,A,B)

二者不同的部分满足gcd(b1,b2,...,bk,B)>=gcd(b1,b2,...,bk,A)+gcd(b1,b2,...,bk,A,B)
因为gcd(b1,b2,...,bk,A)+gcd(b1,b2,...,bk,A,B)=gcd(b1,b2,...,bk,A)+gcd(b1,b2,...,bk,b1,b2,...,bk,A,B)=gcd(b1,b2,...,bk,A)+gcd(gcd(b1,b2,...,bk,A),gcd(b1,b2,...,bk,B))<=gcd(b1,b2,...,bk,B)

这用到了两个点:

  1. gcd(X,Y)<=|XY|
  2. gcd(b1,b2,...,bk,A)<=gcd(b1,b2,...,bk,B)

因此每次选择使得其和当前b中所有元素的最大公约数最小的那个ai加入到b的末尾满足题意。

优化

g=gcd(a1,a2,...,an)
我们可以在开始计算前,将每个ai除以g,因为这样处理后,gcd(a1,a2,...,an)=1,这意味着,我们选择一部分aib中后,就可以使得gcd(b1,b2,...,bk)变为1
事实上,我们每次选择一个ai都会使得gcd(b)下降,因为如果我们某次选择的ai没有使得gcd(b)下降,则说明gcd(b)已经下降到了1,可以退出迭代了。
最后我们再把结果乘上g

如果不进行这一步操作,则很有可能gcd(b)永远都到不了1。这样的话我们代码中判断到1的部分应该改为g

时间复杂度

因为每个数最多有log2x个可能相同的质因数,因此只需要log2105次添加就可以使得gcd(b)=1

int n;
int a[N];

void solve() {
    cin >> n;
    int gcd_all = 0;
    for (int i = 1; i <= n; i ++) {
        cin >> a[i];
        gcd_all = gcd(gcd_all, a[i]);
    }
    for (int i = 1; i <= n; i ++) {
        a[i] /= gcd_all;
    }
    int cur = 0, cnt = 0;
    int ans = 0;
    for (int i = 1; i <= n; i ++) {
        int min_v = INF;
        for (int j = 1; j <= n; j ++) {
            min_v = min(min_v, gcd(cur, a[j]));
        }
        cur = min_v;
        cnt ++;
        ans += cur;
        if (cur == 1) {
            ans += n - cnt;
            break;
        }
    }
    ans *= gcd_all;
    cout << ans << '\n';
}
posted @   lightmon  阅读(93)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示