Problem p02709 (C++) — buggy submission, verdict: Time Limit Exceeded

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

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

long long MOD = 10000000000 + 7;

bool compare(plli x, plli y) { return x.first > y.first; }

int main() {
  cout << setprecision(10);
  int N;
  cin >> N;
  vector<plli> v(N);

  for (int i = 0; i < N; i++) {
    ll tmp;
    cin >> tmp;
    v.at(i) = make_pair(tmp, i);
  }

  sort(v.begin(), v.end(), compare);

  // cerr << v[0].first << " " << v[0].second << endl;

  vector<vector<ll>> dp(N + 1, vector<ll>(N + 1, 0));
  // dp[i][j] : 左にi個、右にj個入れたときの最大
  for (int k = 1; k <= N; k++) {
    // dp[i][j]: i+j = k を走査する
    for (int i = 0; i <= k; i++) {
      int j = k - i;
      if (i - 1 >= 0)
        dp[i][j] =
            max(dp[i][j],
                dp[i - 1][j] + v[k - 1].first * abs(v[k - 1].second - i + 1));
      if (j - 1 >= 0)
        dp[i][j] =
            max(dp[i][j],
                dp[i][j - 1] + v[k - 1].first * abs(N - j - v[k - 1].second));
    }
  }
  ll ans = 0;
  for (int i = 0; i <= N; i++) {
    ans = max(ans, dp.at(i).at(N - i));
  }
  cout << ans << endl;
}


Error: TLE

Fixed submission:

#include <iostream>
#include <vector>
using namespace std;
typedef long long ll;
typedef ll FLOW;                  // フローを表す型、今回は ll 型
typedef ll COST;                  // コストを表す型、今回は ll 型
const ll MAX_V = 400000 + 2;      // グラフの最大ノード数
const COST INF = 100000000000000; // 十分大きい値

// グラフの辺の構造体
struct Edge {
  ll rev, from, to;
  FLOW cap, icap;
  COST cost;
  Edge(ll r, ll f, ll t, FLOW ca, COST co)
      : rev(r), from(f), to(t), cap(ca), icap(ca), cost(co) {}
};

// グラフ構造体
struct Graph {
  ll V;
  vector<Edge> list[MAX_V];

  Graph(ll n = 0) : V(n) {
    for (ll i = 0; i < MAX_V; ++i)
      list[i].clear();
  }
  void init(ll n = 0) {
    V = n;
    for (ll i = 0; i < MAX_V; ++i)
      list[i].clear();
  }
  void resize(ll n = 0) { V = n; }
  void reset() {
    for (ll i = 0; i < V; ++i)
      for (ll j = 0; j < (ll)list[i].size(); ++j)
        list[i][j].cap = list[i][j].icap;
  }
  inline vector<Edge> &operator[](ll i) { return list[i]; }

  Edge &redge(Edge &e) {
    if (e.from != e.to)
      return list[e.to][e.rev];
    else
      return list[e.to][e.rev + 1];
  }

  void addedge(ll from, ll to, FLOW cap, COST cost) {
    list[from].push_back(Edge((ll)list[to].size(), from, to, cap, cost));
    list[to].push_back(Edge((ll)list[from].size() - 1, to, from, 0, -cost));
  }
};

// 最小費用流を求める関数
COST MinCostFlow(Graph &G, ll s, ll t, FLOW inif) {
  COST dist[MAX_V];
  ll prevv[MAX_V];
  ll preve[MAX_V];

  COST res = 0;
  FLOW f = inif;
  while (f > 0) {
    fill(dist, dist + G.V, INF);
    dist[s] = 0;
    while (true) {
      bool update = false;
      for (ll v = 0; v < G.V; ++v) {
        if (dist[v] == INF)
          continue;
        for (ll i = 0; i < (ll)G[v].size(); ++i) {
          Edge &e = G[v][i];
          if (e.cap > 0 && dist[e.to] > dist[v] + e.cost) {
            dist[e.to] = dist[v] + e.cost;
            prevv[e.to] = v;
            preve[e.to] = i;
            update = true;
          }
        }
      }
      if (!update)
        break;
    }

    if (dist[t] == INF)
      return 0;

    FLOW d = f;
    for (ll v = t; v != s; v = prevv[v]) {
      d = min(d, G[prevv[v]][preve[v]].cap);
    }
    f -= d;
    res += dist[t] * d;
    for (ll v = t; v != s; v = prevv[v]) {
      Edge &e = G[prevv[v]][preve[v]];
      Edge &re = G.redge(e);
      e.cap -= d;
      re.cap += d;
    }
  }
  return res;
}

int main() {

  ll N;
  cin >> N;
  ll v[N];
  for (ll i = 0; i < N; i++) {
    cin >> v[i];
  }

  // グラフの定義 (ノード数を引数に)
  Graph G(N + N + 2); // +2 は S, T の分

  // スーパーノード S, T の index
  ll S_node = 2 * N;
  ll T_node = 2 * N + 1;

  // グラフに枝を張っていく
  for (ll i = 0; i < N; ++i) {
    for (ll j = 0; j < N; ++j) {
      // 従業員 i から、仕事 j (index は j+NUM_WORKER) へと、容量 1, コスト
      // -gain の枝を張る
      G.addedge(i, j + N, 1, -v[i] * abs(i - j));
    }
  }

  for (ll i = 0; i < N; ++i) {
    // S から従業員 i へと、容量 2, コスト 0 の枝を張る
    G.addedge(S_node, i, 1, 0);
  }

  for (ll j = 0; j < N; ++j) {
    // 仕事 j から T へと、容量 1, コスト 0 の枝を張る
    G.addedge(j + N, T_node, 1, 0);
  }

  // 最小費用流を求める
  COST res = MinCostFlow(G, S_node, T_node, N);

  // 出力
  cout << -res << endl;

  return 0;
}