返回顶部

Divide by Zero 2021 and Codeforces Round #714 (Div. 2) D. GCD and MST (最小生成树)

  • 题意:有一组数\(a\),如果\(gcd(a_i,a_{i+1},...,a{j})=min(a_i,...,a{i+1},...,a{j})\),那么\(i\)\(j\)之间就可以连一条边,边权为\(min(a_i,...,a{i+1},...,a{j})\).\(i\)\(i+1\)之间都可以连一天边权为\(p\)的边,现在给你这\(n\)个点,求最小生成树.

  • 题解:根据kruskal的贪心思想,我们要求最小生成树,一定是先连边权小的边,所以我们可以对\(a\)先排序,并记录每个\(a_i\)在原数组中的位置,枚举排序后的\(a\),以当前的数同时作为\(gcd\)\(min\),在原数组对应的位置分别向两边拓展连边,并对能连的点标记.

  • 代码:

    #include <bits/stdc++.h>
    #define ll long long
    #define fi first
    #define se second
    #define pb push_back
    #define me memset
    #define rep(a,b,c) for(int a=b;a<=c;++a)
    #define per(a,b,c) for(int a=b;a>=c;--a)
    const int N = 1e6 + 10;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    typedef pair<int,int> PII;
    typedef pair<ll,ll> PLL;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
     
     
    int main(){
        ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
        int _;
        cin>>_;
        while(_--){
            int n,x;
            cin>>n>>x;
    
            vector<int> a(n+1);
            vector<PII> v(n+1);
            vector<bool> st(n+1);
    
            rep(i,1,n){
                cin>>a[i];
                v[i]=(make_pair(a[i],i));
            }
    
            sort(v.begin(),v.end());
    
            ll ans=0;
            rep(i,1,n){
                int cur=v[i].fi;  //cur表示最小因子,去找能匹配的点
                int pos=v[i].se;
    
                if(cur>=x) break;
    
                while(pos>1){
                    if(a[pos-1]%cur==0 && !st[pos-1]){
                        st[pos-1]=true;
                        ans+=cur;
                        pos--;
                    }
                    else break;
                }
                pos=v[i].se;
                while(pos<n){
                    if(a[pos+1]%cur==0 && !st[pos]){
                        st[pos]=true;
                        ans+=cur;
                        pos++;
                    }
                    else break;
                }
            }
    
            rep(i,1,n-1){
                if(!st[i]) ans+=x;
            }
    
            cout<<ans<<'\n';
    
        }
     
     
        return 0;
    }
    
posted @ 2021-04-14 11:33  Rayotaku  阅读(104)  评论(0编辑  收藏  举报