Submission #1265614

#TimeUsernameProblemLanguageResultExecution timeMemory
1265614nguyenhuythachSirni (COCI17_sirni)C++20
140 / 140
2901 ms756864 KiB
#include<bits/stdc++.h>
#include <algorithm>
#include <random>
#include <chrono>
#include <cstdlib>
#include <ctime>
#include <numeric>
#include <vector>
#include <stack>
#include <map>
#include <set>
#include <queue>
#include <iomanip>
using namespace std;
#define ll long long
#define L LLONG_MAX
#define fi first
#define se second
#define pii pair<int,int>
#define sz(a) ((int)a.size())
#define FOR(i,j,k) for(int i=j;i<=k;i++)
#define REP(i,k,j) for(int i=k;i>=j;i--)
#define FORD(i,a) for(auto i:a)
#define rngdcl mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(l,r) ((l)+(rng()%(r-l+1)))

struct triple
{
    int u,v,w;
};

bool operator < (triple a,triple b)
{
    return a.w<b.w;
}

const int nmax=1e5+1;
const int pmax=1e7+1;
int n,mx=0;
vector<pii> p;
vector<triple> edge;
bool cnt[pmax];

void input()
{
    cin >> n;
    FOR(i,1,n)
    {
        int x; cin >> x;
        if(!cnt[x]) p.push_back({x,i});
        cnt[x]=true;
        mx=max(mx,x);
    }
}

struct DSU
{
    vector<int> par;

    DSU() {}
    void init(int n)
    {
        par.resize(n+5,0);
        FOR(i,1,n) par[i]=i;
    }

    int find(int v)
    {
        if(v==par[v]) return v;
        return par[v]=find(par[v]);
    }

    bool joint(int u,int v)
    {
        u=find(u);
        v=find(v);
        if(u!=v)
        {
            par[v]=u;
            return true;
        }
        return false;
    }
};

DSU dsu;

// Counting sort for edges by weight (minimal extra memory: vector<int> freq of size maxw+1)
void counting_sort_edges(vector<triple>& a, int maxw)
{
    if(a.empty()) return;
    int K = maxw + 1;
    vector<int> freq(K);
    for(auto &e: a) ++freq[e.w];
    for(int i=1;i<K;i++) freq[i]+=freq[i-1];
    vector<triple> b(a.size());
    for(int i=(int)a.size()-1;i>=0;--i)
    {
        int w = a[i].w;
        int pos = --freq[w];
        b[pos] = a[i];
    }
    a.swap(b);
    // b freed when function exits
}

void solve()
{
    dsu.init(n);
    sort(p.begin(),p.end());
    FORD(i,p)
    {
        long long cur = (long long)i.fi + 1;
        while (cur <= mx)
        {
            auto it = lower_bound(p.begin(), p.end(), pair<int,int>((int)cur, 0));
            if (it == p.end()) break;
            if (it->se == i.se)
            {
                ++it;
                if (it == p.end()) break;
            }
            edge.push_back({ i.se, (*it).se, (*it).fi % i.fi });
            long long k = (long long)(*it).fi / i.fi;
            cur = (k + 1) * 1LL * i.fi;
        }
    }
    // use counting sort instead of std::sort to avoid TLE
    int maxw = 0;
    for(auto &e: edge) if(e.w > maxw) maxw = e.w;
    counting_sort_edges(edge, maxw);

    int ans=0;
    FORD(i,edge) ans+=dsu.joint(i.u,i.v)*i.w;
    cout << ans;
}

int main()
{
    ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
    input();
    solve();
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...