Problem:
I GCDMST
問題文
$1,\ldots,N$ の番号を振られた $N$ 個の頂点があります。
最初、これらを繋ぐ辺はありません。
あなたはいくつかの辺を追加してこのグラフを連結にしたいと思いました。
頂点 $i$ と $j$ を繋ぐ辺を追加するには $A_{\gcd(i,j)}$ のコストがかかります。
このグラフを連結にするように辺を追加するとき、かかるコストの和の最小値を求めてください。
入力
入力は以下の形式で標準入力から与えられる。
$N$
$A_1$ $\cdots$ $A_N$
制約
入力はすべて整数である。
$2 \leq N \leq 2\times10^5$
$1 \leq A_i \leq 10^9$
出力
答えを 1 行に出力せよ。
入力例1
5
9 7 3 4 8
出力例1
34
例えば $\{1,2\},\{2,4\},\{3,4\},\{4,5\}$ をつなぐ辺をはることで、コスト $34$ でグラフを連結にすることができます。
$\mathrm{gcd}(2,4)$ つまり $2$ と $4$ の最大公約数は $2$ なので $\{2,4\}$ を結ぶ辺のコストは $A_2=7$ です。
入力例2
10
10 8 9 7 6 1 6 7 2 1
出力例2
75

Submitted solutions:

code_snippet: #include <bits/stdc++.h>

using namespace std;
//make -f ../makefile SRC=

/*
brute force => RE or TLE
from index or rather k(th) infers v and w
*/
//------------------------------------------------------------------------------
bool DEBUG = false;
const int INF = 1000000000;

const int MAX_N = 200000;
//static int vect[MAX_N];

//------------------------------------------------------------------------------
struct Element
{
    int i, v;

    Element(): i(-1), v(-INF) {}
    Element(int idx, int val): i(idx), v(val) {}
    bool operator<(const Element& e1) const
    {
        if (v == e1.v) return i < e1.i;
        return v < e1.v;
    }
    void debug() const { printf("i=%d, v=%d\n", i, v); }
};

typedef vector<Element> Elements;
//------------------------------------------------------------------------------
class QuickUnion
{
    public:
    int N;
    int M; // no. of edges
    int* parent;
    int* count_; // no. of nodes rooted at n
    QuickUnion(int num): N(num), M(0)
    {
        parent = new int[N]; // 0-based nodes
        count_ = new int[N];
        for (int n=0; n<N; n++) { parent[n]=n; count_[n]=1; }
    }

    ~QuickUnion() { delete[] parent; delete[] count_; }

    int size(int n) //<--------------------
    {
        int p = root(n);
        return count_[p];
    }

    bool connected()
    {
        return M+1 >= N;
    }

    bool unite(int n1, int n2) //<---------- return true if action is successful
    {
        int r1 = root(n1);
        int r2 = root(n2);
        if (r1==r2) return false;
        M++; //<---------- for checking whether all are connected

        if (count_[r1] < count_[r2]) { parent[r1] = r2; count_[r2] += count_[r1]; }
        else { parent[r2] = r1; count_[r1] += count_[r2]; }
        return true;
    }

    bool find(int n1, int n2)
    {
        return root(n1)==root(n2);
    }

    int root(int node)
    {
        int n = node;
        while (n != parent[n])
        {
            parent[n] = parent[parent[n]]; // vs compression
            n = parent[n];
        }
        parent[node] = n;
        return n;
    }

    void debug() const
    {
        for (int n=0; n<N; n++) printf("node=%d, root=%d\n", n, parent[n]);
        printf("\n");
    }
};

//------------------------------------------------------------------------------
int64_t kruskal(int N, Elements& E)
{
    int64_t res = 0;
    QuickUnion QU(N);
    sort(E.begin(), E.end());
    for (Element e: E)
    {
        if (QU.connected()) break;
        for (int k=1; (e.i+1)*k-1<N; ++k)
        {
            if (QU.unite(e.i, (e.i+1)*k-1))
            {
                res += e.v;
            }
        }
    }
    return res;
}


//------------------------------------------------------------------------------
void test()
{
}

//------------------------------------------------------------------------------
int main()
{
    //DEBUG = true;
    //test(); return 0;
    //--------------------------------------------------------------------------
    int N, K, L, R, v, num;
    num = scanf("%d ", &N);
    Elements E(N);
    for (int n=0; n<N; ++n)
    {
        num = scanf("%d ", &v);
        E[n] = Element(n, v);
    }
    int64_t res = kruskal(N, E);
    printf("%ld\n", res);
    return 0;
}

//------------------------------------------------------------------------------
accuracy: 1
time_ms: 30
memory_kb: 6276
final_rank: 6

code_snippet: // competitive-verifier: PROBLEM
#ifdef ATCODER
#pragma GCC target("sse4.2,avx512f,avx512dq,avx512ifma,avx512cd,avx512bw,avx512vl,bmi2")
#endif
#pragma GCC optimize("Ofast,fast-math,unroll-all-loops")
#include <bits/stdc++.h>
#ifndef ATCODER
#pragma GCC target("sse4.2,avx2,bmi2")
#endif
template <class T, class U>
constexpr bool chmax(T &a, const U &b) {
    return a < (T)b ? a = (T)b, true : false;
}
template <class T, class U>
constexpr bool chmin(T &a, const U &b) {
    return (T)b < a ? a = (T)b, true : false;
}
constexpr std::int64_t INF = 1000000000000000003;
constexpr int Inf = 1000000003;
constexpr double EPS = 1e-7;
constexpr double PI = 3.14159265358979323846;
#define FOR(i, m, n) for (int i = (m); i < int(n); ++i)
#define FORR(i, m, n) for (int i = (m)-1; i >= int(n); --i)
#define FORL(i, m, n) for (int64_t i = (m); i < int64_t(n); ++i)
#define rep(i, n) FOR (i, 0, n)
#define repn(i, n) FOR (i, 1, n + 1)
#define repr(i, n) FORR (i, n, 0)
#define repnr(i, n) FORR (i, n + 1, 1)
#define all(s) (s).begin(), (s).end()
struct Sonic {
    Sonic() {
        std::ios::sync_with_stdio(false);
        std::cin.tie(nullptr);
        std::cout << std::fixed << std::setprecision(20);
    }
    constexpr void operator()() const {}
} sonic;
using namespace std;
using ll = std::int64_t;
using ld = long double;
template <class T, class U>
std::istream &operator>>(std::istream &is, std::pair<T, U> &p) {
    return is >> p.first >> p.second;
}
template <class T>
std::istream &operator>>(std::istream &is, std::vector<T> &v) {
    for (T &i : v) is >> i;
    return is;
}
template <class T, class U>
std::ostream &operator<<(std::ostream &os, const std::pair<T, U> &p) {
    return os << '(' << p.first << ',' << p.second << ')';
}
template <class T>
std::ostream &operator<<(std::ostream &os, const std::vector<T> &v) {
    for (auto it = v.begin(); it != v.end(); ++it) os << (it == v.begin() ? "" : " ") << *it;
    return os;
}
template <class Head, class... Tail>
void co(Head &&head, Tail &&...tail) {
    if constexpr (sizeof...(tail) == 0) std::cout << head << '\n';
    else std::cout << head << ' ', co(std::forward<Tail>(tail)...);
}
template <class Head, class... Tail>
void ce(Head &&head, Tail &&...tail) {
    if constexpr (sizeof...(tail) == 0) std::cerr << head << '\n';
    else std::cerr << head << ' ', ce(std::forward<Tail>(tail)...);
}
void Yes(bool is_correct = true) { std::cout << (is_correct ? "Yes\n" : "No\n"); }
void No(bool is_not_correct = true) { Yes(!is_not_correct); }
void YES(bool is_correct = true) { std::cout << (is_correct ? "YES\n" : "NO\n"); }
void NO(bool is_not_correct = true) { YES(!is_not_correct); }
void Takahashi(bool is_correct = true) { std::cout << (is_correct ? "Takahashi" : "Aoki") << '\n'; }
void Aoki(bool is_not_correct = true) { Takahashi(!is_not_correct); }
/**
 * @brief 素集合データ構造
 * @details Implement (union by size) + (path compression)
 * @see https://github.com/atcoder/ac-library/blob/master/atcoder/dsu.hpp
 */
struct union_find {
    union_find() = default;
    explicit union_find(int _n) : _rank(_n), data(_n, -1) {}
    const int &operator[](std::size_t x) const { return data[x]; }
    int &operator[](std::size_t x) { return data[x]; }
    int root(int x) { return data[x] < 0 ? x : data[x] = root(data[x]); }
    int get_root(int x) { return root(x); }
    bool is_root(int x) const { return data[x] < 0; }
    bool same(int x, int y) { return root(x) == root(y); }
    bool is_same(int x, int y) { return same(x, y); }
    int rank() { return _rank; }
    int size(int x) { return -(data[root(x)]); }
    int get_size(int x) { return size(x); }
    std::vector<int> leaders() {
        std::vector<int> res;
        for (int i = 0; i < (int)data.size(); ++i) {
            if (is_root(i)) res.emplace_back(i);
        }
        return res;
    }
    bool unite(int x, int y) {
        x = root(x), y = root(y);
        if (x == y) return false;
        --_rank;
        if (data[x] > data[y]) std::swap(x, y);
        data[x] += data[y];
        data[y] = x;
        return true;
    }
    template <class F>
    bool unite(int x, int y, F f) {
        x = root(x), y = root(y);
        if (x != y) {
            if (data[x] > data[y]) std::swap(x, y);
            data[x] += data[y];
            data[y] = x;
        }
        f(x, y);
        return x != y;
    }
  private:
    int _rank;
    std::vector<int> data;
};
int main(void) {
    int n;
    cin >> n;
    vector<ll> a(n);
    cin >> a;
    vector<pair<ll, ll>> b(n);
    rep (i, n) b[i] = {a[i], i + 1};
    sort(all(b));
    union_find uf(n);
    ll ans = 0;
    for (auto [x, y] : b) {
        ll p = y - 1;
        while (p + y < n) {
            if (uf.unite(p, p + y))
                ans += x;
            p += y;
        }
    }
    co(ans);
    return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 8888
final_rank: 3

code_snippet: /* -*- coding: utf-8 -*-
 *
 * 3180.cc: GCDMST
 */

#include<cstdio>
#include<vector>
#include<algorithm>
#include<utility>
 
using namespace std;

/* constant */

const int MAX_N = 200000;

/* typedef */

typedef long long ll;
typedef pair<int,int> pii;

struct UFT {
  vector<int> links, ranks, sizes;
  UFT() {}

  void init(int n) {
    links.resize(n);
    for (int i = 0; i < n; i++) links[i] = i;
    ranks.assign(n, 1);
    sizes.assign(n, 1);
  }

  int root(int i) {
    int i0 = i;
    while (links[i0] != i0) i0 = links[i0];
    return (links[i] = i0);
  }

  int rank(int i) { return ranks[root(i)]; }
  int size(int i) { return sizes[root(i)]; }
  bool same(int i, int j) { return root(i) == root(j); }

  int merge(int i0, int i1) {
    int r0 = root(i0), r1 = root(i1), mr;
    if (r0 == r1) return r0;
    if (ranks[r0] == ranks[r1]) {
      links[r1] = r0;
      sizes[r0] += sizes[r1];
      ranks[r0]++;
      mr = r0;
    }
    else if (ranks[r0] > ranks[r1]) {
      links[r1] = r0;
      sizes[r0] += sizes[r1];
      mr = r0;
    }
    else {
      links[r0] = r1;
      sizes[r1] += sizes[r0];
      mr = r1;
    }
    return mr;
  }
};

/* global variables */

int as[MAX_N + 1];
pii ps[MAX_N];
UFT uft;

/* subroutines */

/* main */

int main() {
  int n;
  scanf("%d", &n);
  for (int i = 1; i <= n; i++) scanf("%d", as + i);

  int hn = n / 2;
  for (int i = 1; i <= hn; i++) ps[i - 1] = pii(as[i], i);
  sort(ps, ps + hn);

  uft.init(n + 1);
  ll sum = 0;

  for (int i = 0; i < hn; i++) {
    int aj = ps[i].first, j = ps[i].second;

    for (int k = j * 2; k <= n; k += j) {
      if (! uft.same(j, k)) {
	uft.merge(j, k);
	sum += aj;
      }
    }
  }

  printf("%lld\n", sum);
  return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 6512
final_rank: 2

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using vll = vector<ll>;
using vvll = vector<vll>;
using vvvll = vector<vvll>;
using vb = vector<bool>;
using vvb = vector<vb>;
using vvvb = vector<vvb>;
#define all(A) A.begin(),A.end()
#define rep(i, n) for (ll i = 0; i < (ll) (n); i++)

int main() {

    cin.tie(nullptr);
    ios::sync_with_stdio(false);

    ll N;
    cin>>N;
    vector<pair<ll,ll>> P(N);
    rep(i,N){
        cin>>P[i].first;
        P[i].second=i+1;
    }
    sort(all(P));
    vll L(N+1,0);
    vvll D(N+1);
    rep(i,N){
        L[i+1]=i+1;
        D[i+1].push_back(i+1);
    }
    ll an=0;
    rep(i,N){
        ll a=P[i].first;
        ll b=P[i].second;
        for(ll j=b*2;j<=N;j+=b){
            if(L[j]==L[b])continue;
            //cout<<j<<" "<<b<<endl;
            an+=a;
            if(D[L[j]].size()<D[L[b]].size()){
                for(auto d:D[L[j]]){
                    L[d]=L[b];
                    D[L[b]].push_back(d);
                }
            }
            else{
                for(auto d:D[L[b]]){
                    L[d]=L[j];
                    D[L[j]].push_back(d);
                }
            }
        }
    }
    cout<<an<<endl;
}
accuracy: 1
time_ms: 40
memory_kb: 24076
final_rank: 16

code_snippet: /* -*- coding: utf-8 -*-
 *
 * 3180.cc: GCDMST
 */

#include<cstdio>
#include<vector>
#include<algorithm>
#include<utility>
 
using namespace std;

/* constant */

const int MAX_N = 200000;

/* typedef */

typedef long long ll;
typedef pair<int,int> pii;

struct UFT {
  vector<int> links, ranks, sizes;
  UFT() {}

  void init(int n) {
    links.resize(n);
    for (int i = 0; i < n; i++) links[i] = i;
    ranks.assign(n, 1);
    sizes.assign(n, 1);
  }

  int root(int i) {
    int i0 = i;
    while (links[i0] != i0) i0 = links[i0];
    return (links[i] = i0);
  }

  int rank(int i) { return ranks[root(i)]; }
  int size(int i) { return sizes[root(i)]; }
  bool same(int i, int j) { return root(i) == root(j); }

  int merge(int i0, int i1) {
    int r0 = root(i0), r1 = root(i1), mr;
    if (r0 == r1) return r0;
    if (ranks[r0] == ranks[r1]) {
      links[r1] = r0;
      sizes[r0] += sizes[r1];
      ranks[r0]++;
      mr = r0;
    }
    else if (ranks[r0] > ranks[r1]) {
      links[r1] = r0;
      sizes[r0] += sizes[r1];
      mr = r0;
    }
    else {
      links[r0] = r1;
      sizes[r1] += sizes[r0];
      mr = r1;
    }
    return mr;
  }
};

/* global variables */

int as[MAX_N + 1];
pii ps[MAX_N];
UFT uft;

/* subroutines */

/* main */

int main() {
  int n;
  scanf("%d", &n);
  for (int i = 1; i <= n; i++) scanf("%d", as + i);

  int hn = n / 2;
  for (int i = 1; i <= hn; i++) ps[i - 1] = pii(as[i], i);
  sort(ps, ps + hn);

  uft.init(n + 1);
  ll sum = 0;

  for (int i = 0; i < hn; i++) {
    int aj = ps[i].first, j = ps[i].second;

    for (int k = 2; k * j <= n; k++) {
      int u = (k - 1) * j, v = k * j;
      if (! uft.same(u, v)) {
	uft.merge(u, v);
	sum += aj;
      }
    }
  }

  printf("%lld\n", sum);
  return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 6492
final_rank: 1

code_snippet: #include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <array>
#include <algorithm>
#include <numeric>
#include <unordered_map>
#include <unordered_set>
#include <map>
#include <set>
#include <cassert>
#include <iterator>
#include <random>
#include <stack>
#include <climits>
#include <chrono>
#include <iomanip>


int gcd(const int a, const int b) {
	return (b == 0) ? a : gcd(b, a % b);
}
class UnionFind {
	std::vector<int> vec;
public:
	UnionFind(const int size) : vec(size, -1) {};
	int find(const int a) {
		return vec[a] < 0 ? a : vec[a] = find(vec[a]);
	}
	bool same(const int a, const int b) {
		return find(a) == find(b);
	}
	void unite(int a, int b) {
		a = find(a);
		b = find(b);
		if (a == b) return;
		if (vec[a] > vec[b]) std::swap(a, b);
		vec[a] += vec[b];
		vec[b] = a;
	}
};
int main() {
	int n; std::cin >> n;
	std::vector<int> cost(n);
	for (auto& a : cost) {
		std::cin >> a;
	}
	std::vector<int> order_by_cost(n); std::iota(order_by_cost.begin(), order_by_cost.end(), 0);
	std::sort(order_by_cost.begin(), order_by_cost.end(), [&](const auto i, const auto j) {return cost[i] < cost[j]; });
	long long int result{ 0 };
	UnionFind uft(n);
	for (const auto g : order_by_cost) {
		for (auto i = g; i + g + 1 < n; i += g + 1) {
			if (uft.same(i, i + g + 1)) continue;
			uft.unite(i, i + g + 1);
			result += cost[g];
		}
	}
	std::cout << result << '\n';
}
accuracy: 1
time_ms: 60
memory_kb: 5480
final_rank: 14

code_snippet: #pragma GCC optimize("Ofast")
#include <iostream>
#include <vector>
#include <algorithm>
#include <map>
#include <queue>
#include <cstdio>
#include <ctime>
#include <assert.h>
#include <chrono>
#include <random>
#include <numeric>
#include <set>
#include <deque>
#include <stack>
#include <sstream>
#include <utility>
#include <cstring>
#include <unordered_map>
#include <unordered_set>
#include <tuple>
#include <array>
#include <bitset>
using namespace std;
typedef long long int ll;
typedef unsigned long long ull;

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
ll myRand(ll B) {
    return (ull)rng() % B;
}
inline ll time() {
    return static_cast<long double>(chrono::duration_cast<chrono::nanoseconds>(chrono::steady_clock::now().time_since_epoch()).count()) * 1e-9;
}

struct UnionFind{
    vector<int> par,num;
    UnionFind(int n):par(n),num(n,1){
        iota(par.begin(),par.end(),0);  //include<numeric>
    }
    int find(int v){
        return (par[v]==v)?v:(par[v]=find(par[v]));
    }
    void unite(int u,int v){
        u=find(u),v=find(v);
        if(u==v)return;
        if(num[u]<num[v])swap(u,v);
        num[u]+=num[v];
        par[v]=u;
    }
    bool same(int u,int v){
        return find(u) == find(v);
    }
    int size(int v){
        return num[find(v)];
    }
};

int main(){
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    int n; cin >> n;
    UnionFind uf(n+1);
    vector<pair<int,int>> v(n);
    for(int i=0;i<n;i++){
        cin >> v[i].first;
        v[i].second = i+1;
    }
    sort(v.begin(), v.end());
    ll res = 0;
    for(auto p:v){
        int i = p.second;
        for(int j=i+i;j<=n;j+=i){
            if(!uf.same(i,j)){
                uf.unite(i, j);
                res += p.first;
            }
        }
    }
    cout << res << endl;
}
accuracy: 1
time_ms: 30
memory_kb: 6280
final_rank: 7

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 200005

struct Info{
	Info(ll arg_value,ll arg_index){
		value = arg_value;
		index = arg_index;
	}
	bool operator<(const struct Info &arg) const{

		return value < arg.value;
	}
	ll value,index;
};

int N;
int boss[SIZE],height[SIZE];
vector<Info> info;

int get_boss(int id){
	if(boss[id] == id)return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

int isSame(int x,int y){
	return get_boss(x) == get_boss(y);
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	if(boss_x == boss_y)return;

	if(height[boss_x] > height[boss_y]){

		boss[boss_y] = boss_x;

	}else if(height[boss_x] < height[boss_y]){

		boss[boss_x] = boss_y;

	}else{ //height[boss_x] == height[boss_y]

		boss[boss_y] = boss_x;
		height[x]++;
	}
}

int main(){

	int N;
	scanf("%d",&N);

	for(int i = 1; i <= N; i++){
		boss[i] = i;
		height[i] = 0;
	}

	ll tmp;

	for(int i = 1; i <= N; i++){

		scanf("%lld",&tmp);
		info.push_back(Info(tmp,i));
	}
	sort(info.begin(),info.end());

	ll ans = 0;
	for(int i = 0; i < info.size(); i++){

		for(ll k = 2*(info[i].index); k <= N; k += info[i].index){
			if(isSame(info[i].index,k))continue;

			unite(info[i].index,k);

			ans += info[i].value;
		}
	}

	printf("%lld\n",ans);

	return 0;
}
accuracy: 1
time_ms: 40
memory_kb: 8552
final_rank: 12

code_snippet: #ifdef ONLINE_JUDGE
#pragma GCC target("avx2,avx")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#endif
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ull = unsigned long long;
using i128 = __int128_t;
using pii = pair<int, int>;
using pll = pair<long long, long long>;
#define rep(i, n) for(int i = 0; i < (n); ++i)
#define all(x) (x).begin(),(x).end()
constexpr char ln = '\n';
istream& operator>>(istream& is, __int128_t &x) {
    x = 0;
    string s;
    is >> s;
    int n = int(s.size()), it = 0;
    if (s[0] == '-') it++;
    for (; it < n; it++) x = (x * 10 + s[it] - '0');
    if (s[0] == '-') x = -x;
    return is;
}
ostream& operator<<(ostream& os, __int128_t x) {
    if (x == 0) return os << 0;
    if (x < 0) os << '-', x = -x;
    deque<int> deq;
    while (x) deq.emplace_front(x % 10), x /= 10;
    for (int e : deq) os << e;
    return os;
}
template<class T1, class T2>
ostream& operator<<(ostream& os, const pair<T1, T2>& p) {
    return os << "(" << p.first << ", " << p.second << ")";
}
template<class T> 
ostream& operator<<(ostream& os, const vector<T>& v) {
    os << "[";
    for(auto e : v) os << e << ", ";
    return os << "]";
}
template<class Container> inline int SZ(Container& v) {return int(v.size());}
template<class T1, class T2> inline bool chmax(T1 &a, T2 b) {if (a < b) {a = b; return true;} return false;}
template<class T1, class T2> inline bool chmin(T1 &a, T2 b) {if (a > b) {a = b; return true;} return false;}
inline int topbit(int x) {return x == 0 ? -1 : 31 - __builtin_clz(x);}
inline int topbit(long long x) {return x == 0 ? -1 : 63 - __builtin_clzll(x);}
inline int botbit(int x) {return x == 0 ? 32 : __builtin_ctz(x);}
inline int botbit(long long x) {return x == 0 ? 64 : __builtin_ctzll(x);}
inline int popcount(int x) {return __builtin_popcount(x);}
inline int popcount(long long x) {return __builtin_popcountll(x);}
inline int kthbit(long long x, int k) {return (x>>k)&1;}
inline constexpr long long TEN(int x) {return x == 0 ? 1 : TEN(x-1) * 10;}
namespace detail {
    template<typename Tp, int Nb>
    auto make_vector(vector<int>& sizes, Tp const& x) {
        if constexpr (Nb == 1) {
            return vector(sizes[0], x);
        } else {
            int size = sizes[Nb-1];
            sizes.pop_back();
            return vector(size, make_vector<Tp, Nb-1>(sizes, x));
        }
    }
}
template<typename Tp, int Nb>
auto make_vector(int const(&sizes)[Nb], Tp const& x = Tp()) {
    vector<int> s(Nb);
    for (int i = 0; i < Nb; i++) s[i] = sizes[Nb-i-1];
    return detail::make_vector<Tp, Nb>(s, x);
}
inline void print() {cout << "\n";}
template<class T>
inline void print(const vector<T>& v) {
    for (auto itr = v.begin(); itr != v.end(); ++itr) cout << *itr << " ";
    print();
}
template<class T, class... Args>
inline void print(const T &x, const Args &... args) {
    cout << x << " ";
    print(args...);
}
#ifdef MINATO_LOCAL
#define dump(x) cerr << __LINE__ << " : " << #x << " = " << (x) << endl;
inline void debug() {cerr << endl;}
template<class T>
inline void debug(const vector<T> &v) {
    for (auto itr = v.begin(); itr != v.end(); ++itr) cerr << *itr << " ";
    debug();
}
template<class T, class... Args>
inline void debug(const T &x, const Args &... args) {
    cerr << x << " ";
    debug(args...);
}
#else
#define dump(x) void(0)
inline void debug() {}
template<class T> inline void debug(const vector<T> &v) {}
template<class T, class... Args> inline void debug(const T &x, const Args &... args) {}
#endif
struct Fast_ios {Fast_ios() {cin.tie(nullptr); ios::sync_with_stdio(false); cout << fixed << setprecision(20);};} fast_ios;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

struct UnionFind {
    int N;
    vector<int> node;

    UnionFind(){}
    UnionFind(int N) : N(N), node(N,-1) {}

    void init(int x) {
        node.assign(x,-1);
        N = x;
    }

    bool merge(int x, int y) {
        x = root(x); y = root(y);
        if (x == y) return false;
        if (node[x] > node[y]) swap(x,y);
        node[x] += node[y];
        node[y] = x;
        N--;
        return true; 
    }

    bool same(int x, int y) {return root(x) == root(y);}

    int root(int x) {
        if (node[x] < 0) return x;
        return node[x] = root(node[x]);
    }

    int size(int x) {return -node[root(x)];}

    int count() const {return N;}
};

int main() {
    int N; cin >> N;
    vector<ll> A(N+1,1e18);
    rep(i,N) cin >> A[i+1];

    vector<int> idx(N+1);
    iota(all(idx),0);
    sort(all(idx),[&](int i, int j){return A[i] < A[j];});
    UnionFind uf(N+1);
    ll ans = 0;
    rep(i,N) {
        int u = idx[i];
        for (int j = 2*u; j <= N; j += u) {
            if (uf.merge(j,j-u)) {
                ans += A[u];
            }
        }
    }

    cout << ans << ln;
}
accuracy: 1
time_ms: 30
memory_kb: 6248
final_rank: 5

code_snippet: #include <bits/stdc++.h>
using namespace std;

#define rep(i, m, n) for(int(i) = (int)(m); i < (int)(n); ++i)
#define rep2(i, m, n) for(int(i) = (int)(n)-1; i >= (int)(m); --i)
#define REP(i, n) rep(i, 0, n)
#define REP2(i, n) rep2(i, 0, n)
#define all(hoge) (hoge).begin(), (hoge).end()
#define en '\n'
using ll = long long;
using ull = unsigned long long;
template <class T>
using vec = vector<T>;
template <class T>
using vvec = vector<vec<T>>;
typedef pair<ll, ll> P;
using tp = tuple<ll, ll, ll>;
constexpr long long INF = 1LL << 60;
constexpr int INF_INT = 1 << 25;
//constexpr long long MOD = (ll)1e9 + 7;
constexpr long long MOD = 998244353LL;
using ld = long double;
static const ld pi = 3.141592653589793L;
typedef vector<ll> Array;
typedef vector<Array> Matrix;

template <class T>
inline bool chmin(T &a, T b) {
    if(a > b) {
        a = b;
        return true;
    }
    return false;
}
template <class T>
inline bool chmax(T &a, T b) {
    if(a < b) {
        a = b;
        return true;
    }
    return false;
}

//グラフ関連
struct Edge {
    ll to, cap, rev;
    Edge(ll _to, ll _cap, ll _rev) {
        to = _to;
        cap = _cap;
        rev = _rev;
    }
};
typedef vector<Edge> Edges;
typedef vector<Edges> Graph;

void add_edge(Graph &G, ll from, ll to, ll cap, bool revFlag, ll revCap) {
    G[from].push_back(Edge(to, cap, (ll)G[to].size()));
    if(revFlag)
        G[to].push_back(Edge(from, revCap, (ll)G[from].size() - 1));
}

class UnionFind {
    vector<int> data;
    int num;

  public:
    UnionFind(int size) : data(size, -1), num(size) {}
    bool unionSet(int x, int y) {
        x = root(x);
        y = root(y);
        if(x != y) {
            if(data[y] < data[x])
                swap(x, y);
            data[x] += data[y];
            data[y] = x;
            num--;
        }
        return x != y;
    }
    bool findSet(int x, int y) {
        return root(x) == root(y);
    }
    int root(int x) {
        return data[x] < 0 ? x : data[x] = root(data[x]);
    }
    int size(int x) {
        return -data[root(x)];
    }
    int numSet() {
        return num;
    }
};

void solve() {
    ll n;
    cin >> n;
    vec<P> a(n);

    REP(i, n) {
        cin >> a[i].first;
        a[i].second = i + 1;
    }
    sort(all(a));

    UnionFind uni(n + 1);
    ll ans = 0;
    REP(i, n) {
        auto [cost, k] = a[i];
        for(int j = 2; j * k <= n; j++) {
            if(uni.unionSet(k, j * k)) {
                ans += cost;
            }
        }
    }
    cout << ans << en;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    /*
    ll t;
    cin >> t;
    while(t--)*/
    solve();

    return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 7032
final_rank: 9

code_snippet: #include <bits/stdc++.h>
using namespace std;

#define int long long
//BEGIN CUT HERE
struct UnionFind{
  int num;//連結成分の数
  vector<int> r,p;//そのグループのサイズ,自分の親っぽいやつ
  UnionFind(){}
  UnionFind(int n):num(n),r(n,1),p(n,0){iota(p.begin(),p.end(),0);}

  int find(int x){//どのグループに所属するか
    return (x==p[x]?x:p[x]=find(p[x]));//xがグループの名前と一致するまでxを親にする
  }

  bool same(int x,int y){//同じグループかどうか
    return find(x)==find(y);
  }

  void unite(int x,int y){//xとyを同じグループにする
    x=find(x);y=find(y);//xとyのグループの名前をどっちかが変える
    if(x==y) return;
    if(r[x]<r[y]) swap(x,y);//サイズが大きい方をxとする
    r[x]+=r[y];//yの親をxにする（今までyだったグループ名がxになる）
    p[y]=x;
    num--;
  }

  int size(int x){//グループの大きさ
    return r[find(x)];
  }

  int count() const{//グループの数
    return num;
  }
};
  //END CUT HERE
typedef pair<int,int> P;

signed main(){
  int n;cin>>n;
  vector<P> v(n);
  UnionFind uf(n);
  for(int i=0;i<n;i++){
    int a;cin>>a;v[i]=P(a,i+1);
  }
  int ans=0;
  sort(v.begin(),v.end());
  for(int i=0;i<n;i++){
    int p=v[i].second;
    for(int j=2*p;j<=n;j+=p){
      if(uf.same(p-1,j-1))continue;
      uf.unite(p-1,j-1);
      ans+=v[i].first;
    }
  }
  cout<<ans<<endl;
}
accuracy: 1
time_ms: 70
memory_kb: 9168
final_rank: 15

code_snippet: #include <bits/stdc++.h>
using namespace std;

using Int = long long;
const char newl = '\n';

template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;}
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;}
template<typename T> void drop(const T &x){cout<<x<<endl;exit(0);}
template<typename T=Int>
vector<T> read(size_t n){
  vector<T> ts(n);
  for(size_t i=0;i<n;i++) cin>>ts[i];
  return ts;
}


struct UnionFind{
  Int num;
  vector<Int> rs,ps;
  UnionFind(){}
  UnionFind(Int n):num(n),rs(n,1),ps(n,0){iota(ps.begin(),ps.end(),0);}
  Int find(Int x){
    return (x==ps[x]?x:ps[x]=find(ps[x]));
  }
  bool same(Int x,Int y){
    return find(x)==find(y);
  }
  void unite(Int x,Int y){
    x=find(x);y=find(y);
    if(x==y) return;
    if(rs[x]<rs[y]) swap(x,y);
    rs[x]+=rs[y];
    ps[y]=x;
    num--;
  }
  Int size(Int x){
    return rs[find(x)];
  }
  Int count() const{
    return num;
  }
};

//INSERT ABOVE HERE
signed main(){
  cin.tie(0);
  ios::sync_with_stdio(0);

  Int n;
  cin>>n;

  auto as=read(n);
  as.emplace(as.begin(),0);
  using P = pair<Int, Int>;
  vector<P> vp;
  for(Int i=1;i<=n;i++)
    vp.emplace_back(as[i],i);

  sort(vp.begin(),vp.end());

  UnionFind uf(n+1);

  Int ans=0;
  for(auto[c,i]:vp){
    set<Int> ss;
    for(Int j=i;j<=n;j+=i)
      ss.emplace(uf.find(j));
    ans+=c*(ss.size()-1);
    for(Int j=i;j<=n;j+=i)
      uf.unite(i,j);
  }
  cout<<ans<<newl;
  return 0;
}
accuracy: 1
time_ms: 80
memory_kb: 20668
final_rank: 18

code_snippet: #include <bits/stdc++.h>
using namespace std;
template <class T> inline bool chmax(T &a, T b) {
    if(a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <class T> inline bool chmin(T &a, T b) {
    if(a > b) {
        a = b;
        return 1;
    }
    return 0;
}
#define DEBUG
#ifdef DEBUG
void debug_out() { cerr << endl; }
template <typename Head, typename... Tail> void debug_out(Head H, Tail... T) {
    cerr << " " << H;
    debug_out(T...);
}
#define debug(...)                                                             \
    cerr << __LINE__ << " [" << #__VA_ARGS__ << "]: ", debug_out(__VA_ARGS__)
#define dump(x) cerr << __LINE__ << " " << #x << " = " << (x) << endl
#else
#define debug(...) (void(0))
#define dump(x) (void(0))
#endif

struct Setup {
    Setup() {
        cin.tie(0);
        ios::sync_with_stdio(false);
        cout << fixed << setprecision(15);
    }
} __Setup;

using ll = long long;
#define ALL(v) (v).begin(), (v).end()
#define RALL(v) (v).rbegin(), (v).rend()
const double EPS = 1e-7;
const int INF = 1 << 30;
const ll LLINF = 1LL << 60;
constexpr int MOD = 1000000007;
const int dx[4] = {1, 0, -1, 0};
const int dy[4] = {0, 1, 0, -1};

//-------------------------------------

struct UnionFind {
    vector<int> par;

    UnionFind(int n) : par(n, -1) {}
    void init(int n) { par.assign(n, -1); }

    int root(int x) {
        if(par[x] < 0)
            return x;
        else
            return par[x] = root(par[x]);
    }

    bool issame(int x, int y) { return root(x) == root(y); }

    bool merge(int x, int y) {
        x = root(x);
        y = root(y);
        if(x == y)
            return false;
        if(par[x] > par[y])
            swap(x, y); // merge technique
        par[x] += par[y];
        par[y] = x;
        return true;
    }

    int size(int x) { return -par[root(x)]; }
};

struct edge {
    int from, to;
    ll cost;
    edge() = default;
    edge(int from, int to, ll cost) : from(from), to(to), cost(cost) {}
};

int main() {
    int n;
    cin >> n;
    vector<ll> a(n);
    for(auto &i : a) {
        cin >> i;
    }

    vector<edge> edges;
    for(int i = 1; i <= n; i++) {
        for(int j = 2 * i; j <= n; j += i) {
            edges.emplace_back(edge(i - 1, j - 1, a[i - 1]));
        }
    }

    sort(ALL(edges),
         [](const edge &l, const edge &r) { return (l.cost < r.cost); });
    UnionFind uf(n);

    ll ans = 0;
    for(auto e : edges) {
        if(!uf.issame(e.from, e.to)) {
            uf.merge(e.from, e.to);
            ans += e.cost;
        }
    }

    cout << ans << "\n";
}
accuracy: 1
time_ms: 80
memory_kb: 72280
final_rank: 19

code_snippet: #include <bits/stdc++.h>
//#include <chrono>
//#pragma GCC optimize("Ofast")
using namespace std;
#define reps(i,s,n) for(int i = s; i < n; i++)
#define rep(i,n) reps(i,0,n)
#define Rreps(i,n,e) for(int i = n - 1; i >= e; --i)
#define Rrep(i,n) Rreps(i,n,0)
#define ALL(a) a.begin(), a.end()
#define fi first
#define se second

using ll = long long;
using vec = vector<ll>;
using mat = vector<vec>;

ll N,M,H,W,Q,K,A,B;
string S;
typedef pair<ll, ll> P;
const ll INF = (1LL<<60);

int main() {
    class union_find {
        vector<long> parent, tree_size;
    public:
        union_find(unsigned long _n) : parent(_n), tree_size(_n, 1) {
            for (unsigned long i = 0; i < _n; ++i) parent[i] = i;
        }

        ll find(ll x) {
            while (parent[x] != x)x = parent[x] = parent[parent[x]];
            return x;
        }

        void merge(ll a, ll b) {
            a = find(a);
            b = find(b);
            if (a == b) return;
            if (tree_size[a] < tree_size[b])swap(a, b);
            tree_size[a] += tree_size[b];
            parent[b] = a;
        }

        bool same(ll a, ll b) {
            a = find(a);
            b = find(b);
            return a == b;
        }
    };
    cin>>N;
    vec a(N + 1, INF), ord(N + 1);
    rep(i, N) cin>>a[i + 1];
    iota(ALL(ord), 0);
    sort(ALL(ord), [&](int x, int y){
        return a[x] < a[y];
    });
    union_find uf(N + 1);
    ll res(0);
    rep(i, N){
        int id = ord[i];
        for(int j = id * 2; j <= N; j += id){
            if(!uf.same(id, j)){
                res += a[id];
                uf.merge(j, id);
            }
        }
    }
    cout<<res<<endl;
}
accuracy: 1
time_ms: 80
memory_kb: 9232
final_rank: 17

code_snippet: // #define _GLIBCXX_DEBUG // for STL debug (optional)
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <string>
#include <cstring>
#include <deque>
#include <list>
#include <queue>
#include <stack>
#include <vector>
#include <utility>
#include <algorithm>
#include <map>
#include <set>
#include <complex>
#include <cmath>
#include <limits>
#include <cfloat>
#include <climits>
#include <ctime>
#include <cassert>
#include <numeric>
#include <fstream>
#include <functional>
#include <bitset>
using namespace std;
using ll = long long int;
using int64 = long long int;
 
template<typename T> void chmax(T &a, T b) {a = max(a, b);}
template<typename T> void chmin(T &a, T b) {a = min(a, b);}
template<typename T> void chadd(T &a, T b) {a = a + b;}
 
int dx[] = {0, 0, 1, -1};
int dy[] = {1, -1, 0, 0};
const int INF = 1LL << 29;
const ll LONGINF = 1LL << 60;
const ll MOD = 1000000007LL;

/**
 * @brief Union-Find
 * @docs ./docs/union_find.md
 */

#include <algorithm>
#include <vector>

struct UnionFind {
private:
    const int n;
    int size_;
    vector<int> uf;
public:
    // 初期化 UnionFind uni(n) のように宣言すれば良い
    UnionFind(int _n) : n(_n), size_(_n), uf(_n, -1) {}
    // find (木の根を求める)
    int find(int x) {return (uf[x] < 0) ? x : uf[x] = find(uf[x]);}
    // x と y が同じ集合に属するかどうか
    bool same(int x, int y) {return find(x) == find(y);}
    // x が属する集合の要素数
    int size(int x) {return -uf[find(x)];}
    // 集合はいくつあるか
    int size()      {return size_;}
    // x と y の属する集合を併合
    bool unite(int x, int y) {
        x = find(x); y = find(y);
        if(x == y) return false;
        size_--;
        if(-uf[x] < -uf[y]) swap(x, y);
        uf[x] += uf[y]; uf[y] = x;
        return true;
    }
};

int main() {
    int N; scanf("%d", &N);
    vector<int> A(N), ord(N);
    for(int i=0; i<N; i++) {
        scanf("%d", &A[i]);
        ord[i] = i;
    }
    sort(ord.begin(), ord.end(), [&](auto x, auto y) {
            return A[x] < A[y];
        });

    ll ans = 0;
    UnionFind uf(N);
    for(int i=0; i<N; i++) {
        int v = A[ ord[i] ], k = ord[i];
        for(int j=k; j<N; j+=k+1) {
            if(!uf.same(k, j)) {
                uf.unite(k, j);
                ans += v;
            }
        }
    }
    printf("%lld\n", ans);
    return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 5504
final_rank: 4

code_snippet: #include <iostream>
#include <algorithm>
#include <numeric>
#include <vector>

struct UnionFind {
    std::vector<int> par, sz;
    int gnum;

    explicit UnionFind(int n)
        : par(n), sz(n, 1), gnum(n) {
        std::iota(par.begin(), par.end(), 0);
    }

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

    void unite(int u, int v) {
        u = find(u), v = find(v);
        if (u == v) return;

        if (sz[u] < sz[v]) std::swap(u, v);
        sz[u] += sz[v];
        par[v] = u;
        --gnum;
    }

    bool same(int u, int v) { return find(u) == find(v); }
    bool ispar(int v) { return v == find(v); }
    int size(int v) { return sz[find(v)]; }
};

using lint = long long;

void solve() {
    int n;
    std::cin >> n;

    std::vector<std::pair<lint, int>> ps(n);
    for (int i = 0; i < n; ++i) {
        auto& [x, j] = ps[i];
        std::cin >> x;
        j = i + 1;
    }
    std::sort(ps.begin(), ps.end());

    UnionFind uf(n + 1);
    lint ans = 0;
    for (auto [x, g] : ps) {
        for (int i = g * 2; i <= n; i += g) {
            if (uf.same(g, i)) continue;
            uf.unite(g, i);
            ans += x;
        }
    }

    std::cout << ans << "\n";
}

int main() {
    std::cin.tie(nullptr);
    std::ios::sync_with_stdio(false);

    solve();

    return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 7824
final_rank: 11

code_snippet: // #ifdef LOCAL
// #define _GLIBCXX_DEBUG
// #endif
#include <bits/stdc++.h>
using namespace std;

#pragma region aliases

#define rep(i, n) for(long long i = 0; i < (n); i++)
#define rrep(i, n) for(long long i = (n)-1; i > -1; i--)
#define Rep(i, m, n) for(long long i = (m); i < (n); i++)
#define rRep(i, m, n) for(long long i = (n)-1; i >= (m); i--)
#define REP(i, m, n, p) for(long long i = m; i < n; i += p)
#define foa(s, v) for(auto &s : v)
#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()
#define bcnt(n) __builtin_popcountll(n)
#define endk endl
#define ednl endl
#define enld endl

using ll = long long;
using ld = long double;
using ull = unsigned long long;
using vb = vector<bool>;
using vi = vector<int>;
using vvi = vector<vector<int>>;
using vvvi = vector<vector<vector<int>>>;
using vll = vector<ll>;
using vvll = vector<vll>;
using vvvll = vector<vvll>;
using mll = map<long long, long long>;
using pll = pair<long long, long long>;
using qll = queue<long long>;
using sll = set<long long>;
using vpll = vector<pair<long long, long long>>;
template <class T = ll>
using V = vector<T>;
template <class T = ll>
using VV = V<V<T>>;
template <class T = ll>
using VVV = V<V<V<T>>>;
//昇順pq(小さい方から取り出す)
template <class T = ll>
using pqup = priority_queue<T, vector<T>, greater<T>>;
//降順pq(大きい方から取り出す)
template <class T = ll>
using pqdn = priority_queue<T>;

#pragma endregion

#pragma region constants

long long const limLL = 9223372036854775807;  // POW(2,63)-1 ~ 9.22e18
long long const dekai = 3e16;
const long double pi = acos(-1);
const char dl = '\n';
int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};
int ddx[8] = {-1, -1, -1, 0, 0, 1, 1, 1};
int ddy[8] = {-1, 0, 1, -1, 1, -1, 0, 1};

const int mod = 1000000007;
// const int mod = 998244353;

#pragma endregion

#pragma region basic_procedure

template <class T>
inline bool isin(T x, T lef, T rig) {
	return ((lef <= x) && (x < rig));
}

template <class T>
inline bool chmin(T &a, T b) {
	if(a > b) {
		a = b;
		return true;
	}
	return false;
}
template <class T>
inline bool chmax(T &a, T b) {
	if(a < b) {
		a = b;
		return true;
	}
	return false;
}

void Yes(bool f = 1) { cout << (f ? "Yes" : "No") << "\n"; }
void No() { cout << "No\n"; }
void YES(bool f = 1) { cout << (f ? "YES" : "NO") << "\n"; }
void NO() { cout << "NO\n"; }
template <class T>
void drop(T answer) {
	cout << answer << "\n";
	exit(0);
}
void err() {
	cout << -1 << "\n";
	exit(0);
}

template <class T>
void vout(vector<T> &v, bool tate = 0) {
	if(v.size() > 0) {
		for(auto it = v.begin(); it < v.end(); it++) {
			cout << *it;
			if(it != v.end() - 1) {
				if(tate)
					cout << endl;
				else
					cout << " ";
			}
		}
	}
	cout << endl;
}

template <class T>
void add(vector<T> &v, T val) {	 //ベクトルの各要素に加算
	for(auto &a : v) a += val;
	return;
}

// vectorの中身を数える map<要素,個数>を返す
template <class T>
map<T, long long> cntv(vector<T> v) {
	map<T, long long> m;
	for(auto &g : v) {
		if(m.count(g))
			m[g]++;
		else
			m[g] = 1;
	}
	return m;
}

//配列圧縮
//{1,36,1,3,8,-2,-92}を
//{2, 5,2,3,4, 1,  0}にする
template <class T>
vector<long long> press(vector<T> &v) {
	long long n = v.size();
	vector<long long> w(n);
	map<T, long long> m;
	for(T &p : v) m[p] = 0;
	long long i = 0;
	for(auto &p : m) {
		p.second = i;
		i++;
	}
	for(long long i = 0; i < n; i++) w.at(i) = m[v.at(i)];
	return w;
}

// 切り上げ除算
template <class T>
T dup(T a, T b) {
	assert(b != 0);
	T x = abs(a);
	T y = abs(b);
	T z = (x + y - 1) / y;
	if((a < 0 && b > 0) || (a > 0 && b < 0))
		return -z;
	else if(a == 0)
		return 0;
	else
		return z;
}

long long POW(long long a, long long n) {
	long long res = 1;
	while(n > 0) {
		if(n & 1) res = res * a;
		a = a * a;
		n >>= 1;
	}
	return res;
}

long long modpow(long long a, long long n, long long mod) {	 // a^n mod
	if(mod == 1) return 0LL;
	long long res = 1;
	while(n > 0) {
		if(n & 1) res = res * a % mod;
		a = a * a % mod;
		n >>= 1;
	}
	return res;
}

// a * x % mod == __gcd(a,mod)なるxを返す
// a が modの倍数でないことが条件
long long modinv(long long a, long long mod) {
	long long b = mod, u = 1, v = 0;
	while(b) {
		long long t = a / b;
		a -= t * b;
		swap(a, b);
		u -= t * v;
		swap(u, v);
	}
	u %= mod;
	if(u < 0) u += mod;
	return u;
}

vector<vector<long long>> comb(100, vector<long long>(100, -1));
long long com(long long n, long long k) {  //普通の二項計数(overflowに注意)
	assert(n < 100 && k < 100);
	if(n < k || k < 0 || n < 0) return 0;
	if(comb[n][k] != -1) return comb[n][k];
	ll res;
	if(n - k < k)
		res = com(n, n - k);
	else if(k == 0)
		res = 1;
	else
		res = com(n - 1, k - 1) + com(n - 1, k);
	comb[n][k] = res;
	return res;
}

// nCk modを求める
const int MAX = 5100000;
// この値は求める二項計数の値に応じて変える
// MAX=3*10^7のとき1900msほど、ほぼ比例
// MAX=5*10^6程度ならそれほど気にしなくてよい(300ms程)
long long fac[MAX], finv[MAX], inv[MAX];

void cominit() {
	// テーブルを作る前処理
	fac[0] = fac[1] = 1;
	finv[0] = finv[1] = 1;
	inv[1] = 1;
	for(int i = 2; i < MAX; i++) {
		fac[i] = fac[i - 1] * i % mod;
		inv[i] = mod - inv[mod % i] * (mod / i) % mod;
		finv[i] = finv[i - 1] * inv[i] % mod;
	}
}
long long commod(long long n, long long k) {  // 二項係数
	if(n < k) return 0;
	if(n < 0 || k < 0) return 0;
	return fac[n] * (finv[k] * finv[n - k] % mod) % mod;
}
long long pmod(long long n, long long k) {	// 順列
	if(n < k) return 0;
	if(n < 0 || k < 0) return 0;
	return fac[n] * finv[n - k] % mod;
}
// n個の区別しないボールを区別するk個の箱に入れる方法の総数
long long hmod(long long n, long long k) {	// 重複組み合わせ
	return commod(n + k - 1, n);
}
#pragma endregion

#pragma region input
#define VEC(type, name, size) \
	vector<type> name(size);  \
	INPUT(name)
#define VVEC(type, name, h, w)                     \
	vector<vector<type>> name(h, vector<type>(w)); \
	INPUT(name)
#define INT(...)     \
	int __VA_ARGS__; \
	INPUT(__VA_ARGS__)
#define LL(...)            \
	long long __VA_ARGS__; \
	INPUT(__VA_ARGS__)
#define STR(...)        \
	string __VA_ARGS__; \
	INPUT(__VA_ARGS__)
#define CHAR(...)     \
	char __VA_ARGS__; \
	INPUT(__VA_ARGS__)
#define DOUBLE(...)     \
	double __VA_ARGS__; \
	INPUT(__VA_ARGS__)
#define LD(...)              \
	long double __VA_ARGS__; \
	INPUT(__VA_ARGS__)

template <class T>
void scan(T &a) {
	cin >> a;
}
template <class T>
void scan(vector<T> &a) {
	for(auto &i : a) scan(i);
}
template <class T, class L>
void scan(pair<T, L> &p) {
	scan(p.first);
	scan(p.second);
}
void INPUT() {}
template <class Head, class... Tail>
void INPUT(Head &head, Tail &... tail) {
	scan(head);
	INPUT(tail...);
}
template <class T>
inline void print(T x) {
	cout << x << '\n';
}

template <typename T1, typename T2>
istream &operator>>(istream &is, pair<T1, T2> &p) {
	is >> p.first >> p.second;
	return is;
}
#pragma endregion

#pragma region debug

#pragma region output
template <typename T1, typename T2>
ostream &operator<<(ostream &os, const pair<T1, T2> &p) {
	os << p.first << " " << p.second;
	return os;
}
template <class T>
ostream &operator<<(ostream &os, const vector<T> &v) {
	for(int i = 0; i < (int)v.size(); i++) {
		if(i) os << " ";
		os << v[i];
	}
	return os;
}
#pragma endregion

#pragma region view

template <typename T>
void view(const T e) {
	std::cerr << e;
}

template <typename T, typename U>
void view(const std::pair<T, U> &p) {
	std::cerr << "(";
	view(p.first);
	cerr << ", ";
	view(p.second);
	cerr << ")";
}

template <typename T>
void view(std::set<T> &s) {
	if(s.empty()) {
		cerr << "{ }";
		return;
	}
	std::cerr << "{ ";
	for(auto &t : s) {
		view(t);
		std::cerr << ", ";
	}
	std::cerr << "\b\b }";
}

template <typename T>
void view(const std::vector<T> &v) {
	if(v.empty()) {
		cerr << "{ }";
		return;
	}
	std::cerr << "{ ";
	for(const auto &e : v) {
		view(e);
		std::cerr << ", ";
	}
	std::cerr << "\b\b }";
}

template <typename T>
void view(const std::vector<std::vector<T>> &vv) {
	std::cerr << "{\n";
	for(const auto &v : vv) {
		std::cerr << "\t";
		view(v);
		std::cerr << "\n";
	}
	std::cerr << "}";
}

template <typename T, typename U>
void view(const std::vector<std::pair<T, U>> &v) {
	std::cerr << "{\n";
	for(const auto &c : v) {
		std::cerr << "\t(";
		view(c.first);
		cerr << ", ";
		view(c.second);
		cerr << ")\n";
	}
	std::cerr << "}";
}

template <typename T, typename U>
void view(const std::map<T, U> &m) {
	std::cerr << "{\n";
	for(auto &t : m) {
		std::cerr << "\t[";
		view(t.first);
		cerr << "] : ";
		view(t.second);
		cerr << "\n";
	}
	std::cerr << "}";
}

#pragma endregion

// when debugging : g++ foo.cpp -DLOCAL
#ifdef LOCAL
void debug_out() {}
template <typename Head, typename... Tail>
void debug_out(Head H, Tail... T) {
	view(H);
	cerr << ", ";
	debug_out(T...);
}
#define debug(...)                                           \
	do {                                                     \
		cerr << __LINE__ << " [" << #__VA_ARGS__ << "] : ["; \
		debug_out(__VA_ARGS__);                              \
		cerr << "\b\b]\n";                                   \
	} while(0)
#define dump(x)                                 \
	do {                                        \
		cerr << __LINE__ << " " << #x << " : "; \
		view(x);                                \
		cerr << "\n";                           \
	} while(0)

#else
#define debug(...) (void(0))
#define dump(x) (void(0))
#endif

#pragma endregion

struct UF {			   // Union_Find木 (平衡操作あり)
	vector<int> data;  // data[root] = -size, data[not_root] = parent
	UF(int N) : data(N) {
		for(int i = 0; i < N; i++) {
			data[i] = -1;
		}
	}
	int root(int x) {
		if(data[x] < 0) return x;
		return data[x] = root(data[x]);
	}
	// 2つのデータx, yが属する木が同じならtrueを返す
	bool same(int x, int y) { return root(x) == root(y); }
	bool unite(int x, int y) {	// xとyの木を併合
		x = root(x);
		y = root(y);
		if(x == y) return false;
		if(data[x] > data[y]) swap(x, y);  // 平衡操作 sizeは-1倍なのでこれで正しい
		data[x] += data[y];
		data[y] = x;
		return true;
	}
	int size(int x) { return -data[root(x)]; }
};

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cout << fixed << setprecision(15);
	srand((unsigned)time(NULL));

	INT(n);
	VEC(ll, a, n);

	pqup<pll> q;
	rep(i, n) { q.push({a[i], i + 1}); }

	UF uf(n);
	ll ans = 0;

	while(!q.empty()) {
		ll sa, cost;
		tie(cost, sa) = q.top();
		q.pop();
		ll b = sa - 1;
		ll c = sa + sa - 1;
		while(c < n) {
			if(uf.unite(b, c)) {
				ans += cost;
			}
			c += sa;
		}
	}
	drop(ans);
	;

	return 0;
}
accuracy: 1
time_ms: 40
memory_kb: 10572
final_rank: 13

code_snippet: #include <iostream>
#include <string>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <unordered_map>
#include <map>
#include <set>
#include <algorithm>
#include <queue>
#include <stack>
#include <functional>
#include <bitset>
#include <assert.h>
#include <unordered_map>
#include <fstream>
#include <ctime>
#include <complex>
using namespace std;
typedef long long ll;
typedef vector<ll> vl;
typedef vector<vl> vvl;
typedef vector<char> vc;
typedef vector<string> vs;
typedef vector<bool> vb;
typedef vector<double> vd;
typedef pair<ll,ll> P;
typedef pair<int,int> pii;
typedef vector<P> vpl;
typedef tuple<ll,ll,ll> tapu;
#define rep(i,n) for(int i=0; i<(n); i++)
#define REP(i,a,b) for(int i=(a); i<(b); i++)
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
const int inf = 1<<30;
const ll linf = 1LL<<62;
const int MAX = 1020000;
ll dy[8] = {1,-1,0,0,1,-1,1,-1};
ll dx[8] = {0,0,1,-1,1,-1,-1,1};
const double pi = acos(-1);
const double eps = 1e-7;
template<typename T1,typename T2> inline bool chmin(T1 &a,T2 b){
	if(a>b){
		a = b; return true;
	}
	else return false;
}
template<typename T1,typename T2> inline bool chmax(T1 &a,T2 b){
	if(a<b){
		a = b; return true;
	}
	else return false;
}
template<typename T> inline void print(T &a){
    for(auto itr = a.begin(); itr != a.end(); itr++){
		cout << *itr << " ";
	}
    cout << "\n";
}
template<typename T1,typename T2> inline void print2(T1 a, T2 b){
	cout << "debug: " << a << " " << b << "\n";
}
template<typename T1,typename T2,typename T3> inline void print3(T1 a, T2 b, T3 c){
	cout << "debug: " << a << " " << b << " " << c << "\n";
}
void mark() {cout << "#" << "\n";}
ll pcount(ll x) {return __builtin_popcountll(x);}
const int mod = 1e9 + 7;
//const int mod = 998244353;

struct UnionFind{
	vl p;
	vl rank;
	vl cnt;

	UnionFind(ll n){
		rank.resize(n,0);
		p.resize(n,0);
		cnt.resize(n,0);
		rep(i,n){
			p[i] = i;
			rank[i] = 0;
			cnt[i] = 1;
		}
	}

	ll find(ll x){
		if(x != p[x]) p[x] = find(p[x]);
		return p[x];
	}

	bool same(ll x, ll y){
		return find(x) == find(y);
	}

	void unite(ll x, ll y){
		x = find(x);
		y = find(y);
		if(x == y) return;
		if(rank[x] > rank[y]){
			p[y] = x;
			cnt[x] += cnt[y];
		}else{
			p[x] = y;
			cnt[y] += cnt[x];
			if(rank[x] == rank[y]) rank[y]++;
		}
	}

	ll size(ll x){
		return cnt[find(x)];
	}
};

int main(){
	int n; cin >> n;
	vl a(n); rep(i,n) cin >> a[i];
	UnionFind uf(n);
	vector<tapu> edges;
	for(int i=1; i<=n; i++){
		for(int j=i; j+i<=n; j+=i){
			edges.emplace_back(a[i-1],j-1,j+i-1);
		}
	}
	sort(all(edges));
	ll ans = 0;
	for(auto e : edges){
		ll cost, u, v;
		tie(cost, u, v) = e;
		if(uf.same(u,v)) continue;
		uf.unite(u,v);
		ans += cost;
	}
	cout << ans << "\n";
}
accuracy: 1
time_ms: 290
memory_kb: 107580
final_rank: 20

code_snippet: #include <bits/stdc++.h>
#define For(i, a, b) for (int(i) = (int)(a); (i) < (int)(b); ++(i))
#define rFor(i, a, b) for (int(i) = (int)(a)-1; (i) >= (int)(b); --(i))
#define rep(i, n) For((i), 0, (n))
#define rrep(i, n) rFor((i), (n), 0)
#define fi first
#define se second
using namespace std;
typedef long long lint;
typedef unsigned long long ulint;
typedef pair<int, int> pii;
typedef pair<lint, lint> pll;
template <class T>
bool chmax(T &a, const T &b) {
    if (a < b) {
        a = b;
        return true;
    }
    return false;
}
template <class T>
bool chmin(T &a, const T &b) {
    if (a > b) {
        a = b;
        return true;
    }
    return false;
}
template <class T>
T div_floor(T a, T b) {
    if (b < 0) a *= -1, b *= -1;
    return a >= 0 ? a / b : (a + 1) / b - 1;
}
template <class T>
T div_ceil(T a, T b) {
    if (b < 0) a *= -1, b *= -1;
    return a > 0 ? (a - 1) / b + 1 : a / b;
}

constexpr lint mod = 1000000007;
constexpr lint INF = mod * mod;
constexpr int MAX = 100010;

typedef struct UnionFindTree {
    vector<int> par;

    UnionFindTree(int n) { par.resize(n, -1); }

    bool is_root(int x) { return par[x] < 0; }

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

    int size(int x) { return -par[find(x)]; }

    bool unite(int x, int y) {
        x = find(x);
        y = find(y);
        if (x == y) return false;
        if (size(x) < size(y)) swap(x, y);
        par[x] += par[y];
        par[y] = x;
        return true;
    }

    bool same(int x, int y) { return find(x) == find(y); }
} UF;

int main() {
    int n;
    scanf("%d", &n);
    vector<pair<lint, int>> a(n);
    rep(i, n) {
        scanf("%lld", &a[i].fi);
        a[i].se = i + 1;
    }
    sort(a.begin(), a.end());
    lint ans = 0;
    UF uf(n + 1);
    for (auto &p : a) {
        for (int k = 1; p.se * k <= n; ++k) {
            if (uf.unite(p.se, p.se * k)) ans += p.fi;
        }
    }
    printf("%lld\n", ans);
}
accuracy: 1
time_ms: 30
memory_kb: 7024
final_rank: 8

code_snippet: #include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<utility>
#include<cassert>
#include<complex>
#include<numeric>
using namespace std;

//#define int long long
typedef long long ll;

typedef unsigned long long ul;
typedef unsigned int ui;
constexpr ll mod = 1000000007;
const ll INF = mod * mod;
typedef pair<int, int>P;
#define stop char nyaa;cin>>nyaa;
#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
#define all(v) (v).begin(),(v).end()
typedef pair<ll, ll> LP;
typedef double ld;
typedef pair<ld, ld> LDP;
const ld eps = 1e-12;
const ld pi = acos(-1.0);

struct uf {
private:
	vector<int> par, ran;
public:
	uf(int n) {
		par.resize(n, 0);
		ran.resize(n, 0);
		rep(i, n) {
			par[i] = i;
		}
	}
	int find(int x) {
		if (par[x] == x)return x;
		else return par[x] = find(par[x]);
	}
	void unite(int x, int y) {
		x = find(x), y = find(y);
		if (x == y)return;
		if (ran[x] < ran[y]) {
			par[x] = y;
		}
		else {
			par[y] = x;
			if (ran[x] == ran[y])ran[x]++;
		}
	}
	bool same(int x, int y) {
		return find(x) == find(y);
	}
};
int gcd(int a, int b) {
	if (a < b)swap(a, b);
	while (b) {
		int r = a % b; a = b; b = r;
	}
	return a;
}


void solve() {
	int n; cin >> n;
	vector<ll> a(n + 1);
	rep1(i, n)cin >> a[i];
	vector<P> pairs;
	rep1(i, n)pairs.push_back({ a[i],i });
	sort(all(pairs));
	uf u(n + 1);
	ll ans = 0;
	for (P p : pairs) {
		int val = p.first;
		int g = p.second;
		for (int i = 2 * g; i <= n; i += g) {
			if (!u.same(i, g)) {
				u.unite(i, g);
				ans += val;
			}
		}
	}
	cout << ans << "\n";
}





signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	solve();
	return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 7520
final_rank: 10