zoukankan      html  css  js  c++  java
  • D. GCD and MST 思维 + 数论

    D. GCD and MST 思维 + 数论

    题目大意:

    有n个点排成一行。每个点有一个值。对于第i到j个点,如果i到j这一部分所有点的值的gcd等于所有点的值的min,那么这两点之间有一条边,长度就为所有点的值的min。此外,如果j=i+1,这两个点之间还会有一条长度为k的边。请你找出这n个点的最小生成树。

    题解:

    • 首先可以知道, (gcd(a_i,a_{i+1},...,a_j)=min(a_i,a_{i+1},...,a_j)) 假设最小值是 (a_x) ,那么其实就是找到一个区间 ([l,r]) (x) 属于这个区间,并且 (a_x) 整除这个区间任意一个数。
    • 所以假设此时最小值是 (a_x) ,那么我从 (x) 往右,从 (x) 往左找到一个整除的区间 ([l,r]) ,然后继续找下一个最小值 (a_y) ,如果 (y) 属于区间 ([l,r]) ,那么就不需要找了,如果不在,那么找他的整除区间,与前面的区间不重叠。
    • 然后可以用一个线性的写法 (ans[i]) 表示 (i) 这个位置的贡献,假设 (n) 为根节点。
    • 对于每一个点 (i) 往后枚举整除的区间,如果整除的 (ans[j]<=a[i]) ,那么就停止往前找。
      • 这个是因为如果 (ans[j]<=a[i]) ,那么说明 (ans[j]) 是被一个小于 (a[i]) 的值更新了,并且这个值的位置在 (i) 前面,那么可以说明 (ans[j]) 也整除 (a[i]) ,所以后面的值如果可以被 (a[i]) 更新,那么一定也可以被 (ans[j]) 更新。
    • 总的来说,其实就是找到一个点去更新左右两边的点,然后加上一些优化。
    • 但是这个过程中要注意,如果 (x,y) 是一个连通块的,那么 (a[x]) 更新了 (ans[y]) ,那么 (ans[x]) 就不能由 (a[y]) 更新。
    • 最后求总和之后,找到一个 (ans[x]) 最大的值减去就是答案。
    • 复杂度分析:
      • 如果你理解了这个做法应该可以很容易发现这个是一个 (O(n))
      • 因为对于每一个数 (x) ,只会往后更新到不是他的倍数了
      • 那么会不会 (x) 后面有一个数会重复更新这个区间呢?
      • 加上后面有一个数 (y) ,也是在 (x) 更新的这个区间之内,那么 (a[y]>=a[x])
      • 往后更新,如果 (ans[y+1]=a[x]) ,那么 (y) 是会立即停止的,因为 (ans[y+1]<=a[y])
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn = 2e5 + 10;
    int a[maxn],ans[maxn];
    int main(){
        int T;
        scanf("%d",&T);
        while(T--){
            int n,p;
            scanf("%d%d",&n,&p);
            for(int i=1;i<=n;i++) scanf("%d",&a[i]),ans[i] = p;
            for(int i=1;i<=n;i++){
                for(int j=i;j<n;j++){
                    if(a[j+1]%a[i]!=0||ans[j]<=a[i]) break;
                    ans[j] = a[i];
                }
            }
            for(int i=n;i>=1;i--){
                for(int j=i-1;j>=1;j--){
                    if(a[j]%a[i]!=0||ans[j]<=a[i]) break;
                    ans[j] = a[i];
                }
            }
            ll res = 0;
            int maxs = 0;
            for(int i=1;i<=n;i++) res += ans[i],maxs = max(maxs,ans[i]);
            printf("%lld
    ",res - maxs);
        }
        return 0;
    }
    
    
  • 相关阅读:
    7-感觉身体被掏空,但还是要学Pandas(下)
    6-感觉身体被掏空,但还是要学Pandas(上)
    5-Numpy似双丝网,中有千千结(下)
    4-Numpy似双丝网,中有千千结(上)
    3-上帝说要有光,于是就有了Python(下)
    2-上帝说要有光,于是就有了Python(上)
    1-在IPython Notebook中愉快地使用python编程
    第11组 Alpha冲刺(2/6)
    第11组 Alpha冲刺(1/6)
    2019 SDN上机第2次作业
  • 原文地址:https://www.cnblogs.com/EchoZQN/p/14658826.html
Copyright © 2011-2022 走看看