Language: C++

#ifndef __GRAPH_H__
#define __GRAPH_H__

#include <vector>
#include <cstdint>
#include <iostream>
#include <string>
#include <sstream>

struct GraphEdge {
	int from = 0;
	int to = 0;

	GraphEdge() = default;
	GraphEdge(int from, int to);
};

/* 有向グラフクラス(特に無向グラフクラスは用意せず、両方向に辺を張ることで対応する) */
class Graph {
public:
	using EdgeID = int;
	using Edge = GraphEdge;
	using List = std::vector<EdgeID>;

private:
	std::vector<List> ids_m;
 	std::vector<Edge> edges_m;

public:
	Graph() = default;
	Graph(Graph&&) = default;
	Graph(const Graph&) = default;
	Graph& operator=(Graph&&) = default;
	Graph& operator=(const Graph&) = default;

	explicit Graph(int size);
	int size() const;
	int edgeCount() const;
	void init(int new_size);
	void reserve(int edge_count);
	
	void add(int from, int to);
	const List& row(int from) const;
	const Edge& getEdge(EdgeID id) const;
	const std::vector<Edge>& getEdges() const;
	EdgeID reverseEdgeOf(EdgeID id) const;

	std::string toString() const;
	void debug() const;
};

Graph inputGraph(int size, int edge_count, bool directed = true, bool one_based = true, std::istream& ist = std::cin);
// outputGraph

template <class T>
class WeightedGraph {
	Graph graph_m;
	std::vector<T> weights_m;

public:
	WeightedGraph() = default;
	WeightedGraph(WeightedGraph&&) = default;
	WeightedGraph(const WeightedGraph&) = default;
	WeightedGraph& operator=(WeightedGraph&&) = default;
	WeightedGraph& operator=(const WeightedGraph&) = default;

	explicit WeightedGraph(int size);
	void init(int new_size);
	void add(int from, int to, T&& weight);
	void add(int from, int to, const T& weight);

	const Graph& getGraph() const;
	const std::vector<T>& getWeights() const;

	std::string toString() const;
	void debug() const;
};

template<class T>
inline WeightedGraph<T>::WeightedGraph(int size) 
	: graph_m(size) {
}

template<class T>
inline void WeightedGraph<T>::init(int new_size) {
	graph_m.init(new_size);
}

template<class T>
inline void WeightedGraph<T>::add(int from, int to, T&& weight) {
	graph_m.add(from, to);
	weights_m.push_back(std::move(weight));
}

template<class T>
inline void WeightedGraph<T>::add(int from, int to, const T& weight) {
	graph_m.add(from, to);
	weights_m.push_back(weight);
}

template<class T>
inline const Graph& WeightedGraph<T>::getGraph() const {
	return graph_m;
}

template<class T>
inline const std::vector<T>& WeightedGraph<T>::getWeights() const {
	return weights_m;
}

template<class T>
inline std::string WeightedGraph<T>::toString() const {
	std::ostringstream stream;
	for (int from = 0; from < graph_m.size(); ++from) {
		stream << from << ": [";
		for (auto id : graph_m.row(from)) {
			const auto& edge = graph_m.getEdge(id);
			int to = edge.to;
			stream << ' ' << to << '(' << weights_m[id] << ')';
		}
		stream << " ]" << std::endl;
	}
	return stream.str();
}

template<class T>
inline void WeightedGraph<T>::debug() const {
	std::cerr << toString() << std::endl;
}

template <class T>
WeightedGraph<T> inputWeightedGraph(int size, int edge_count, bool directed = true, bool one_based = true, std::istream& ist = std::cin);

template <class T>
WeightedGraph<T> inputWeightedGraph(int size, int edge_count, bool directed, bool one_based, std::istream& ist) {
	WeightedGraph<T> ret(size);
	for (int j = 0; j < edge_count; ++j) {
		int a, b;
		T weight;
		ist >> a >> b >> weight;
		if (one_based) {
			--a; --b;
		}

		if (directed) {
			ret.add(a, b, weight);
		} else {
			ret.add(a, b, weight);
			ret.add(b, a, weight);
		}
	}
	return ret;
}

#endif

#ifdef ONLY_MY_ENVIR
#include "Graph.h"
#endif

#include <cassert>
#include <sstream>

GraphEdge::GraphEdge(int from, int to)
	: from(from), to(to) {
}

Graph::Graph(int size) 
	: ids_m(size) {
}

int Graph::size() const {
	return ids_m.size();
}

int Graph::edgeCount() const {
	return edges_m.size();
}

void Graph::init(int new_size) {
	assert(new_size >= size());
	ids_m.resize(new_size);
}

void Graph::reserve(int edge_count) {
	edges_m.reserve(edge_count);
}

void Graph::add(int from, int to) {
	ids_m[from].push_back(edges_m.size());
	edges_m.push_back(Edge(from, to));
}

const Graph::List& Graph::row(int from) const {
	assert(from >= 0 && from < size());
	return ids_m[from];
}

const Graph::Edge& Graph::getEdge(EdgeID id) const {
	assert(id >= 0 && id < edgeCount());
	return edges_m[id];
}

const std::vector<Graph::Edge>& Graph::getEdges() const {
	return edges_m;
}

/* 無向グラフ用: 逆辺を参照する */
Graph::EdgeID Graph::reverseEdgeOf(EdgeID id) const {
	return id ^ 0x1;
}

std::string Graph::toString() const {
	std::ostringstream stream;
	for (int from = 0; from < size(); ++from) {
		stream << from << ": [";
		for (auto id : row(from)) {
			const auto& edge = getEdge(id);
			int to = edge.to;
			stream << ' ' << to;
		}
		stream << " ]" << std::endl;
	}
	return stream.str();
}

void Graph::debug() const {
	std::cerr << toString() << std::endl;
}

Graph inputGraph(int size, int edge_count, bool directed, bool one_based, std::istream& ist) {
	Graph ret(size);
	for (int j = 0; j < edge_count; ++j) {
		int a, b;
		ist >> a >> b;
		if (one_based) {
			--a; --b;
		}

		if (directed) {
			ret.add(a, b);
		} else {
			ret.add(a, b);
			ret.add(b, a);
		}
	}
	return ret;
}
#ifndef __FLOW_SOLVER__
#define __FLOW_SOLVER__

/* updated: 2019-10-04 */

#ifdef ONLY_MY_ENVIR
#include "Graph.h"
#endif

#include <vector>
#include <algorithm>
#include <limits>
#include <queue>

using CapacityType = long long;
struct GraphEdgeWithReverse {
	int to_m;
	CapacityType capacity_m;
	int rev_index_m;		  // グラフの一要素(逆辺の入っている)における逆辺の添字(ポインタにする手もある)

	GraphEdgeWithReverse(int to, CapacityType capacity, int rev_index);
};

/* 本当は自動的に逆辺の容量を調整するのがよさそう */
class GraphWithReverse {
public:
	typedef GraphEdgeWithReverse Edge;
private:
	std::vector<Edge>* edges_m;
	int size_m;

public:
	GraphWithReverse(int size);
	~GraphWithReverse();

	int size() const;
	std::vector<Edge>* data();

	void add(int from, int to, CapacityType capacity, bool bidirected);
};

/* 使い切り */
class FlowSolver {
	static const CapacityType InfCapacity;
	static const int CannotReach;

private:
	GraphWithReverse graph_m;

	CapacityType fordFulkersonSubRec(int from, int sink, CapacityType curr_max_flow, bool* used_p);
	CapacityType fordFulkersonSub(int source, int sink, bool* used_p);

	void calcDistance(int start, int* dist_p);
	CapacityType dinicSubRec(int from, int sink, CapacityType curr_max_flow, int* done_index_p, int* dist_p);
	CapacityType dinicSub(int source, int sink, int* done_index_p, int* dist_p);

public:
	FlowSolver(const WeightedGraph<CapacityType>& wgraph);

	/* source, sink は頂点番号 */

	/* O(E * Maxflow) */
	CapacityType fordFulkerson(int source, int sink);
	/* O(E * V ** 2) */
	CapacityType dinic(int source, int sink);
};


#endif

#ifdef ONLY_MY_ENVIR
#include "FlowSolver.h"
#endif

/*--------------------------------------------*/
/*---------   GraphEdgeWithReverse   ---------*/
/*--------------------------------------------*/

GraphEdgeWithReverse::GraphEdgeWithReverse(int to, CapacityType capacity, int rev_index)
	:to_m(to), capacity_m(capacity), rev_index_m(rev_index) {
}

GraphWithReverse::GraphWithReverse(int size)
	:size_m(size) {
	edges_m = new std::vector<Edge>[size_m];
}

GraphWithReverse::~GraphWithReverse() {
	delete[] edges_m;
}

int GraphWithReverse::size() const {
	return size_m;
}

std::vector<GraphWithReverse::Edge>* GraphWithReverse::data() {
	return edges_m;
}

void GraphWithReverse::add(int from, int to, CapacityType capacity, bool bidirected) {
	if (bidirected) {
		add(from, to, capacity, false);
		add(to, from, capacity, false);
		return;
	}
	
	edges_m[from].push_back(Edge(to, capacity, edges_m[to].size()));
	edges_m[to].push_back(Edge(from, 0, edges_m[from].size() - 1));
}

/*----------------------------------*/
/*---------   FlowSolver   ---------*/
/*----------------------------------*/

const CapacityType FlowSolver::InfCapacity = std::numeric_limits<CapacityType>::max();
const int FlowSolver::CannotReach = -1;

CapacityType FlowSolver::fordFulkersonSubRec(int from, int sink, CapacityType curr_max_flow, bool* used_p) {
	if (from == sink) return curr_max_flow;
	used_p[from] = true;

	typedef std::vector<GraphWithReverse::Edge> GraphDataType;
	GraphDataType* data_p = graph_m.data();
	for (auto&& edge : data_p[from]) {
		if (used_p[edge.to_m] || edge.capacity_m <= 0) continue;
		CapacityType flow = fordFulkersonSubRec(edge.to_m, sink, std::min(curr_max_flow, edge.capacity_m), used_p);
		if (flow > 0) {
			edge.capacity_m -= flow;
			data_p[edge.to_m][edge.rev_index_m].capacity_m += flow;
			return flow;
		}
	}
	return 0;
}

CapacityType FlowSolver::fordFulkersonSub(int source, int sink, bool* used_p) {
	const int size = graph_m.size();
	std::fill(used_p, used_p + size, false);
	return fordFulkersonSubRec(source, sink, InfCapacity, used_p);
}

void FlowSolver::calcDistance(int start, int* dist_p) {
	typedef std::vector<GraphWithReverse::Edge> GraphDataType;
	const int size = graph_m.size();
	std::fill(dist_p, dist_p + size, CannotReach);
	GraphDataType* data_p = graph_m.data();

	std::queue<int> dist_queue;
	dist_p[start] = 0;
	dist_queue.push(start);
	while (!dist_queue.empty()) {
		int from = dist_queue.front(); dist_queue.pop();
		for (auto&& edge : data_p[from]) {
			if (dist_p[edge.to_m] != CannotReach || edge.capacity_m <= 0) continue;
			dist_p[edge.to_m] = dist_p[from] + 1;
			dist_queue.push(edge.to_m);
		}
	}
}

CapacityType FlowSolver::dinicSubRec(int from, int sink, CapacityType curr_max_flow, int* done_index_p, int* dist_p) {
	if (from == sink) return curr_max_flow;

	typedef std::vector<GraphWithReverse::Edge> GraphDataType;
	GraphDataType* data_p = graph_m.data();
	for (int& i = done_index_p[from]; i < data_p[from].size(); ++i) {		// i は done_index_p[from] の別名
		GraphWithReverse::Edge& edge = data_p[from][i];
		if (dist_p[edge.to_m] <= dist_p[from] || edge.capacity_m <= 0) continue;
		CapacityType flow = dinicSubRec(edge.to_m, sink, std::min(curr_max_flow, edge.capacity_m), done_index_p, dist_p);
		if (flow > 0) {
			edge.capacity_m -= flow;
			data_p[edge.to_m][edge.rev_index_m].capacity_m += flow;
			return flow;
		}
	}
	return 0;
}

CapacityType FlowSolver::dinicSub(int source, int sink, int* done_index_p, int* dist_p) {
	return dinicSubRec(source, sink, InfCapacity, done_index_p, dist_p);
}

FlowSolver::FlowSolver(const WeightedGraph<CapacityType>& wgraph)
	: graph_m(wgraph.getGraph().size()) {
	const auto& graph = wgraph.getGraph();
	const auto& costs = wgraph.getWeights();

	const int size = graph.size();
	for (int from = 0; from < size; ++from) {
		for (auto id : graph.row(from)) {
			const auto& edge = graph.getEdge(id);
			int to = edge.to;
			CapacityType cost = costs[id];
			graph_m.add(from, to, cost, false);
		}
	}
}

CapacityType FlowSolver::fordFulkerson(int source, int sink) {
	const int size = graph_m.size();
	bool* used_p = new bool[size];
	std::fill(used_p, used_p + size, false);

	CapacityType sum_flow = 0;
	while (true) {
		CapacityType curr_flow = fordFulkersonSub(source, sink, used_p);
		if (curr_flow == 0) break;
		sum_flow += curr_flow;
	}

	delete[] used_p;
	return sum_flow;
}

CapacityType FlowSolver::dinic(int source, int sink) {
	const int size = graph_m.size();
	int* done_index_p = new int[size];
	int* dist_p = new int[size];

	CapacityType sum_flow = 0;
	while (true) {
		calcDistance(source, dist_p);
		if (dist_p[sink] == CannotReach) break;
		std::fill(done_index_p, done_index_p + size, 0);
		while (true) {
			CapacityType curr_flow = dinicSub(source, sink, done_index_p, dist_p);
			if (curr_flow == 0) break;
			sum_flow += curr_flow;
		}
	}

	delete[] done_index_p;
	delete[] dist_p;
	return sum_flow;
}
#define _CRT_SECURE_NO_WARNINGS
#define _SCL_SECURE_NO_WARNINGS
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <utility>
#include <algorithm>
#include <functional>
#include <cmath>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <iomanip>
#include <sstream>
#include <bitset>
#include <limits>
#include <numeric>
#include <valarray>
#include <fstream>
#include <array>
#include <random>
#include <unordered_set>
#include <unordered_map>

using namespace std;
using uint = uint32_t;
using LL = int64_t;
using ULL = uint64_t;
using PP = pair<LL, LL>;
template <typename T> using PriorityQ = priority_queue<T, vector<T>, greater<T> >;
#define REP(i, a, n) for(LL i = (a), i##_max_ = (n); i < i##_max_; ++i)
#define REM(i, a, n) for(LL i = (LL)(n) - 1, i##_min_ = (a); i >= i##_min_; --i)
#define FLOAT fixed << setprecision(16)
#define SPEEDUP { cin.tie(NULL); ios::sync_with_stdio(false); }
const int INF = 0x3FFFFFFF;
const LL INFLL = 0x3FFFFFFF3FFFFFFF;
const double INFD = 1.0e+308;
const double EPS = 1.0e-9;

void YesNo(bool b) { cout << (b ? "Yes" : "No") << endl; }
void YESNO(bool b) { cout << (b ? "YES" : "NO") << endl; }
template <class T, class U> istream& operator>>(istream& ist, pair<T, U>& right) { return ist >> right.first >> right.second; }
template <class T, class U> ostream& operator<<(ostream& ost, const pair<T, U>& right) { return ost << right.first << ' ' << right.second; }
template <class T, class TCompatible, size_t N> void Fill(T(&dest)[N], const TCompatible& val) { fill(dest, dest + N, val); }
template <class T, class TCompatible, size_t M, size_t N> void Fill(T(&dest)[M][N], const TCompatible& val) { for (int i = 0; i < M; ++i) Fill(dest[i], val); }
template <class T> T Next() { T buf; cin >> buf; return buf; }
istream& Ignore(istream& ist) { string s; ist >> s; return ist; }
bool Inside(int i, int j, int h, int w) { return i >= 0 && i < h && j >= 0 && j < w; }

#ifdef ONLY_MY_ENVIR
#include "IntMod.h"
#include "Algebraic.h"
#include "BinaryMatrix.h"
#include "BinaryTree.h"
#include "Bipartite.h"
#include "BIT.h"
#include "DynamicMod.h"
#include "Factorization.h"
#include "FFT.h"
#include "FlowSolver.h"
#include "Graph.h"
#include "LazySegmentTree.h"
#include "Math.h"
#include "Matrix.h"
#include "MinCostFlowSolver.h"
#include "MinMax.h"
#include "Numbers.h"
#include "Polynomial.h"
#include "Position.h"
#include "Range.h"
#include "Rational.h"
#include "SegmentTree.h"
#include "SegmentTree2D.h"
#include "SlidingWindow.h"
#include "StringSeaching.h"
#include "SuffixArray.h"
#include "Tree.h"
#include "UnionFind.h"
#endif

#ifdef __GNUC__
typedef __int128 LLL;
istream& operator>>(istream& ist, __int128& val) { LL tmp; ist >> tmp; val = tmp; return ist; }
ostream& operator<<(ostream& ost, __int128 val) { LL tmp = val; ost << tmp; return ost; }
#endif

int N;
int A[101];
int main() {
	cin >> N;
	REP(i, 1, N + 1) {
		cin >> A[i];
	}

	LL base = 0;
	WeightedGraph<LL> G(N + 2);
	REP(i, 1, N + 1) {
		if (A[i] >= 0) {
			base += A[i];
			G.add(0, i, A[i]);
		} else {
			G.add(i, N + 1, -A[i]);
		}
	}

	REP(i, 1, N + 1) {
		for (int j = 2 * i; j <= N; j += i) {
			G.add(j, i, INFLL);
		}
	}

	FlowSolver fs(G);
	cout << base - fs.dinic(0, N + 1) << endl;
	return 0;
}


Compiler output:
a.cc: In function 'int main()':
a.cc:601:24: error: no matching function for call to 'FlowSolver::FlowSolver(WeightedGraph<long int>&)'
  601 |         FlowSolver fs(G);
      |                        ^
a.cc:431:1: note: candidate: 'FlowSolver::FlowSolver(const WeightedGraph<long long int>&)'
  431 | FlowSolver::FlowSolver(const WeightedGraph<CapacityType>& wgraph)
      | ^~~~~~~~~~
a.cc:431:59: note:   no known conversion for argument 1 from 'WeightedGraph<long int>' to 'const WeightedGraph<long long int>&'
  431 | FlowSolver::FlowSolver(const WeightedGraph<CapacityType>& wgraph)
      |                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~
a.cc:291:7: note: candidate: 'constexpr FlowSolver::FlowSolver(const FlowSolver&)'
  291 | class FlowSolver {
      |       ^~~~~~~~~~
a.cc:291:7: note:   no known conversion for argument 1 from 'WeightedGraph<long int>' to 'const FlowSolver&'
a.cc:291:7: note: candidate: 'constexpr FlowSolver::FlowSolver(FlowSolver&&)'
a.cc:291:7: note:   no known conversion for argument 1 from 'WeightedGraph<long int>' to 'FlowSolver&&'