// Original C++ solution (slower):
//#define __USE_MINGW_ANSI_STDIO 0

#include <bits/stdc++.h>



using namespace std;

typedef long long ll;

#define int ll

typedef vector<int> VI;

typedef vector<VI> VVI;

typedef vector<ll> VL;

typedef vector<VL> VVL;

typedef pair<int, int> PII;



#define FOR(i, a, n) for (ll i = (ll)a; i < (ll)n; ++i)

#define REP(i, n) FOR(i, 0, n)

#define ALL(x) x.begin(), x.end()

#define IN(a, b, x) (a<=x&&x<b)

#define MP make_pair

#define PB push_back

#ifdef int

const ll INF = (1LL<<60);

#else

const int INF = (1LL<<30);

#endif

const double PI = 3.14159265359;

const double EPS = 1e-12;

const int MOD = 1000000007;



template <typename T> T &chmin(T &a, const T &b) { return a = min(a, b); }

template <typename T> T &chmax(T &a, const T &b) { return a = max(a, b); }



int dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0};



#define MAX_N 10000

struct edge{ int to, cap, rev; };



vector<edge> G[MAX_N];

int level[MAX_N]; // sからの距離

int iter[MAX_N];  // どこまで調べ終わったか



void add_edge(int from, int to, int cap) {

  G[from].PB({to, cap, (int)G[to].size()});

  G[to].PB({from, 0, (int)G[from].size()-1});

}



void bfs(int s) {

  memset(level, -1, sizeof(level));

  queue<int> que;

  level[s] = 0;

  que.push(s);

  while(que.size()) {

    int v = que.front(); que.pop();

    for(auto i: G[v]) {

      if(i.cap > 0 && level[i.to] < 0) {

        level[i.to] = level[v] + 1;

        que.push(i.to);

      }

    }

  }

}



int dfs(int v, int t, int f) {

  if(v == t) return f;

  for(int &i = iter[v]; i<(int)G[v].size(); ++i) {

    edge &e = G[v][i];

    if(e.cap > 0 && level[v] < level[e.to]) {

      int d = dfs(e.to, t, min(f, e.cap));

      if(d > 0) {

        e.cap -= d;

        G[e.to][e.rev].cap += d;

        return d;

      }

    }

  }

  return 0;

}



int max_flow(int s, int t) {

  int flow = 0;

  while(1) {

    bfs(s);

    if(level[t] < 0) return flow;

    memset(iter, 0, sizeof(iter));

    int f;

    while((f = dfs(s, t, INF)) > 0) flow += f;

  }

}



int a[105];

signed main(void)

{

  int n;

  cin >> n;

  /* 0～N-1:宝石 N:スタートS N+1:ゴールT */

  int sum = 0;

  REP(i, n) {

    cin >> a[i];

    // 辺を張る

    if(a[i] > 0) add_edge(i, n+1, a[i]);

    else if(a[i] < 0) add_edge(n, i, -a[i]);

    sum += max(0LL, a[i]);

  }

  FOR(i, 1, n+1) {

    for(int j=2*i; j<=n; j+=i) {

      // 頂点iの倍数の頂点jに辺を張る

      add_edge(i-1, j-1, INF);

    }

  }



  cout << sum - max_flow(n, n+1) << endl;



  return 0;

}


// Optimized solution to the same problem (faster):
#include <bits/stdc++.h>

using namespace std;

using ll = long long;

using PII = pair<ll, ll>;

#define FOR(i, a, n) for (ll i = (ll)a; i < (ll)n; ++i)

#define REP(i, n) FOR(i, 0, n)

#define ALL(x) x.begin(), x.end()

template<typename T> void chmin(T &a, const T &b) { a = min(a, b); }

template<typename T> void chmax(T &a, const T &b) { a = max(a, b); }

struct FastIO {FastIO() { cin.tie(0); ios::sync_with_stdio(0); }}fastiofastio;

#ifdef DEBUG_ 

#include "../program_contest_library/memo/dump.hpp"

#else

#define dump(...)

#endif

const ll INF = 1LL<<60;



template<class T>

struct dinic {

    struct edge{

        int to;

        T cap;

        int rev;

        bool isrev;

    };



    vector<vector<edge>> G;

    vector<int> level, iter;



    void bfs(int s) {

        level.assign(G.size(), -1);

        queue<int> que;

        level[s] = 0;

        que.push(s);

        while(que.size()) {

            int v = que.front(); que.pop();

            for(auto i: G[v]) {

                if(i.cap > 0 && level[i.to] < 0) {

                    level[i.to] = level[v] + 1;

                    que.push(i.to);

                }

            }

        }

    }



    T dfs(int v, const int t, T f) {

        if(v == t) return f;

        for(int &i = iter[v]; i<(ll)G[v].size(); ++i) {

            edge &e = G[v][i];

            if(e.cap > 0 && level[v] < level[e.to]) {

                T d = dfs(e.to, t, min(f, e.cap));

                if(d > 0) {

                    e.cap -= d;

                    G[e.to][e.rev].cap += d;

                    return d;

                }

            }

        }

        return 0;

    }



    dinic() {}

    dinic(int n) : G(n), level(n), iter(n) {}



    void add_edge(int from, int to, T cap) {

        G[from].push_back({to, cap, (int)G[to].size(), false});

        G[to].push_back({from, 0, (int)G[from].size()-1, true});

    }



    // sからtへ流量fを流す

    T maxflow(int s, int t, T f = 1LL<<30) {

        T flow = 0;

        while(1) {

            bfs(s);

            if(level[t] < 0) return flow;

            iter.assign(G.size(), 0);

            T tmp;

            while((tmp = dfs(s, t, f)) > 0) flow += tmp;

        }

    }



    // sからtへ1流す

    T flow(int s, int t) {

        bfs(s);

        if(level[t] < 0) return 0;

        iter.assign(G.size(), 0);

        return dfs(s, t, 1);

    }

    // 始点，終点tのフローで辺e=(from,to)の容量を1増やしたときの最大流の変化

    // 並列辺はたぶんバグる

    T add(int from, int to, int s, int t) {

        for(auto &e: G[from]) {

            if(e.to == to && !e.isrev) {

                e.cap++;

                break;

            }

        }

        return flow(s, t);

    }

    // 始点s，終点tのフローで辺e=(from,to)の容量を1減らしたときの最大流の変化

    // 並列辺はたぶんバグる

    T sub(int from, int to, int s, int t) {

        for(auto &e: G[from]) {

            if(e.to == to && !e.isrev) {

                T diff = 0;

                // 辺(from,to)で容量いっぱいに流れている

                if(e.cap == 0) {

                    // 残余グラフでfrom→toのパスがない

                    if(flow(from, to) == 0) {

                        flow(t, to);

                        flow(from, s);

                        diff = -1;

                    }

                    G[e.to][e.rev].cap--;

                } else {

                    e.cap--;

                }

                return diff;

            }

        }

        assert(false); // 存在しない辺を減らそうとした

    }



    friend ostream &operator <<(ostream& out, const dinic& a){

        out << endl;

        for(int i = 0; i < (int)a.G.size(); i++) {

            for(auto &e : a.G[i]) {

                if(e.isrev) continue;

                auto &rev_e = a.G[e.to][e.rev];

                out << i << "->" << e.to << " (flow: " << rev_e.cap << "/" << e.cap + rev_e.cap << ")" << endl;

            }

        }

        return out;

    }

};



int main(void) {

    ll n;

    cin >> n;

    vector<ll> a(n);

    REP(i, n) cin >> a[i];



    dinic<ll> graph(n+2);

    ll s = n, t = s+1;



    ll ret = 0;

    FOR(i, 1, n+1) {

        if(a[i-1] < 0) {

            graph.add_edge(s, i-1, 0);

            graph.add_edge(i-1, t, abs(a[i-1]));

        } else {

            ret += a[i-1];

            graph.add_edge(s, i-1, a[i-1]);

            graph.add_edge(i-1, t, 0);

        }

    }

    FOR(i, 1, n+1) {

        for(ll j=2*i; j<=n; j+=i) {

            // iが割られてる → jも割られてる

            // jが割られてない && iが割られてる → INF失う

            graph.add_edge(j-1, i-1, INF);

        }

    }



    cout << ret - graph.maxflow(s, t) << endl;



    return 0;

}

// Fastest known solution for this problem: