library

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub maspypy/library

:warning: convex/monge/monge_shortest_path_d_edge.hpp

Depends on

Code

#pragma once
#include "convex/larsch.hpp"

// https://codeforces.com/contest/2183/problem/H
template <typename T, typename F>
T monge_shortest_path_d_edge(int N, int d, T flim, F f) {
  assert(1 <= d && d <= N);
  if (d == 1) return f(0, N);
  if (d == N) {
    T ans = 0;
    FOR(i, N) ans += f(i, i + 1);
    return ans;
  }
  if (d == 2) {
    T ans = infty<T>;
    FOR(i, 1, N) chmin(ans, f(0, i) + f(i, N));
    return ans;
  }

  vc<pair<T, int>> dp(N + 1);
  map<T, pair<T, int>> MP;
  T ANS = -infty<T>;
  auto calc = [&](T lambda) -> pair<T, int> {
    if (MP.count(lambda)) return MP[lambda];
    dp[0] = {0, 0};
    auto eval = [&](int i, int j) -> T {
      ++i;
      if (i <= j) return infty<T>;
      return dp[j].fi + f(j, i);
    };
    LARSCH<T, decltype(eval)> larsch(N, eval);

    FOR(r, 1, N + 1) {
      int l = larsch.get_argmin();
      dp[r].fi = dp[l].fi + f(l, r) + lambda;
      dp[r].se = dp[l].se + 1;
    }
    chmax(ANS, dp[N].fi - lambda * d);
    return MP[lambda] = dp[N];
  };

  T lo = -3 * flim - 10, hi = 3 * flim + 10;
  while (lo + 1 < hi) {
    T mi = (lo + hi) / 2;
    int k = calc(mi).se;
    if (k == d) break;
    (k > d ? lo : hi) = mi;
  }
  return ANS;
}
#line 1 "convex/larsch.hpp"
// 制約きつい https://codeforces.com/contest/2183/problem/H
template <class T, class F>
class LARSCH {
  struct reduce_row;
  struct reduce_col;
  struct ColMap {
    const ColMap* parent = nullptr;
    const std::vector<int>* v = nullptr;

    inline int map(int j) const {
      int x = v ? (*v)[j] : j;
      return parent ? parent->map(x) : x;
    }
  };

  struct Eval {
    const F* f = nullptr;
    long long a = 1;  // row = a*i + b
    long long b = 0;
    const ColMap* cm = nullptr;

    inline T operator()(int i, int j) const {
      int ii = int(a * i + b);
      int jj = cm ? cm->map(j) : j;
      return (*f)(ii, jj);
    }
  };

  struct reduce_row {
    int n;
    Eval e;
    int cur_row = 0;
    int state = 0;
    std::unique_ptr<reduce_col> rec;

    reduce_row(int n_, const Eval& e_) : n(n_), e(e_) {
      int m = n / 2;
      if (m) {
        Eval eo = e;
        eo.b = e.a + e.b;
        eo.a = 2 * e.a;
        rec = std::make_unique<reduce_col>(m, eo);
      }
    }

    inline void reset() {
      cur_row = 0;
      state = 0;
      if (rec) rec->reset();
    }

    inline int get_argmin() {
      int i = cur_row++;
      if ((i & 1) == 0) {
        int prev = state;
        int next = (i + 1 == n ? n - 1 : rec->get_argmin());
        state = next;
        int ret = prev;
        for (int j = prev + 1; j <= next; ++j) {
          if (e(i, ret) > e(i, j)) ret = j;
        }
        return ret;
      } else {
        return (e(i, state) <= e(i, i)) ? state : i;
      }
    }
  };

  struct reduce_col {
    int n;
    Eval e;
    int cur_row = 0;
    std::vector<int> cols;
    ColMap cm_here;
    reduce_row rec;

    reduce_col(int n_, const Eval& e_)
        : n(n_),
          e(e_),
          cols(),
          cm_here{e.cm, &cols},
          rec(n_, Eval{e.f, e.a, e.b, &cm_here}) {
      cols.reserve(n);
    }

    inline void reset() {
      cur_row = 0;
      cols.clear();
      rec.reset();
    }

    inline void push_col(int j, int i) {
      while (!cols.empty()) {
        int size = (int)cols.size();
        if (size == i) break;
        int last = cols.back();
        if (e(size - 1, last) > e(size - 1, j))
          cols.pop_back();
        else
          break;
      }
      if ((int)cols.size() != n) cols.push_back(j);
    }

    inline int get_argmin() {
      int i = cur_row++;
      if (i == 0) {
        cols.clear();
        cols.push_back(0);
      } else {
        push_col(2 * i - 1, i);
        push_col(2 * i, i);
      }
      return cols[rec.get_argmin()];
    }
  };

  F f_;
  ColMap root_cm_;
  Eval root_eval_;
  std::unique_ptr<reduce_row> base_;

 public:
  explicit LARSCH(int n, F f)
      : f_(std::move(f)),
        root_cm_{nullptr, nullptr},
        root_eval_{&f_, 1, 0, &root_cm_} {
    base_ = std::make_unique<reduce_row>(n, root_eval_);
  }

  inline void reset() { base_->reset(); }
  inline int get_argmin() { return base_->get_argmin(); }
};
#line 3 "convex/monge/monge_shortest_path_d_edge.hpp"

// https://codeforces.com/contest/2183/problem/H
template <typename T, typename F>
T monge_shortest_path_d_edge(int N, int d, T flim, F f) {
  assert(1 <= d && d <= N);
  if (d == 1) return f(0, N);
  if (d == N) {
    T ans = 0;
    FOR(i, N) ans += f(i, i + 1);
    return ans;
  }
  if (d == 2) {
    T ans = infty<T>;
    FOR(i, 1, N) chmin(ans, f(0, i) + f(i, N));
    return ans;
  }

  vc<pair<T, int>> dp(N + 1);
  map<T, pair<T, int>> MP;
  T ANS = -infty<T>;
  auto calc = [&](T lambda) -> pair<T, int> {
    if (MP.count(lambda)) return MP[lambda];
    dp[0] = {0, 0};
    auto eval = [&](int i, int j) -> T {
      ++i;
      if (i <= j) return infty<T>;
      return dp[j].fi + f(j, i);
    };
    LARSCH<T, decltype(eval)> larsch(N, eval);

    FOR(r, 1, N + 1) {
      int l = larsch.get_argmin();
      dp[r].fi = dp[l].fi + f(l, r) + lambda;
      dp[r].se = dp[l].se + 1;
    }
    chmax(ANS, dp[N].fi - lambda * d);
    return MP[lambda] = dp[N];
  };

  T lo = -3 * flim - 10, hi = 3 * flim + 10;
  while (lo + 1 < hi) {
    T mi = (lo + hi) / 2;
    int k = calc(mi).se;
    if (k == d) break;
    (k > d ? lo : hi) = mi;
  }
  return ANS;
}
Back to top page