// // Monge 単一始点 d-辺最短路の d = 1, 2, ..., D における列挙 (by SMAWK 法, in O(ND)) // // verified // yukicoder No.952 危険な火薬庫 // https://yukicoder.me/problems/no/952 // #include using namespace std; // find min_j f(i, j) for all i, by Monotone Minima, O(H + W log H) // f(i, j) must be totally monotone template void SMAWKRec (const vector &X, const vector &Y, const FUNC &f, vector> &res) { if (X.empty()) return; // Reduce Step vector X2, Y2; for (auto y : Y) { while (!Y2.empty()) { int py = Y2.back(), x = X[(int)Y2.size() - 1]; if (f(x, y) >= f(x, py)) break; Y2.pop_back(); } if (Y2.size() < X.size()) Y2.emplace_back(y); } // Recurse Step for (int i = 1; i < (int)X.size(); i += 2) X2.emplace_back(X[i]); SMAWKRec(X2, Y2, f, res); // Interpolate Step int p = 0; for (int i = 0; i < (int)X.size(); i += 2) { int lim = (i + 1 < (int)X.size() ? res[X[i + 1]].second : Y.back()), best = Y[p]; while (Y[p] < lim) { p++; if (f(X[i], Y[p]) < f(X[i], best)) best = Y[p]; } res[X[i]] = {f(X[i], best), best}; } } template vector> SMAWK(int H, int W, const FUNC &f) { if (H == 0) return {}; assert(W > 0); vector> res(H, make_pair(numeric_limits::max() / 2, -1)); vector X(H), Y(W); for (int i = 0; i < H; i++) X[i] = i; for (int j = 0; j < W; j++) Y[j] = j; SMAWKRec(X, Y, f, res); return res; } // find the d-edges shortest path for d = 1, 2, ..., D, in O(ND) // vertex: 0, 1, 2, ..., N, f(i, j) must be Monge template struct MongeShortestPathWithDEdges { VAL INF = numeric_limits::max() / 2; // solver template vector solve(int N, const FUNC &f, int D) { assert(D <= N); vector res{VAL(0)}, dp(N + 1, INF); dp[0] = 0; auto f2 = [&](int i, int j) -> VAL { return (j < i ? dp[j] + f(j, i) : INF); }; for (int d = 1; d <= D; d++) { const auto &tmp = SMAWK(N + 1, N + 1, f2); for (int i = d; i <= N; i++) dp[i] = tmp[i].first; res.emplace_back(dp[N]); } return res; } }; //------------------------------// // Examples //------------------------------// //------------------------------// // Utility //------------------------------// using ll = long long; using i128 = __int128_t; using u128 = __uint128_t; using pint = pair; using pll = pair; using tll = array; using fll = array; using vint = vector; using vll = vector; using dint = deque; using dll = deque; using vvint = vector>; using vvll = vector>; using vpll = vector>; template using min_priority_queue = priority_queue, greater>; template inline bool chmax(S &a, T b) { return (a < b ? a = b, 1 : 0); } template inline bool chmin(S &a, T b) { return (a > b ? a = b, 1 : 0); } template inline auto maxll(S a, T b) { return max(ll(a), ll(b)); } template inline auto minll(S a, T b) { return min(ll(a), ll(b)); } template auto max(const T &a) { return *max_element(a.begin(), a.end()); } template auto min(const T &a) { return *min_element(a.begin(), a.end()); } template auto argmax(const T &a) { return max_element(a.begin(), a.end()) - a.begin(); } template auto argmin(const T &a) { return min_element(a.begin(), a.end()) - a.begin(); } template auto accum(const vector &a) { return accumulate(a.begin(), a.end(), T()); } template auto accum(const deque &a) { return accumulate(a.begin(), a.end(), T()); } #define REP(i, a) for (long long i = 0; i < (long long)(a); i++) #define REP2(i, a, b) for (long long i = a; i < (long long)(b); i++) #define RREP(i, a) for (long long i = (a)-1; i >= (long long)(0); --i) #define RREP2(i, a, b) for (long long i = (b)-1; i >= (long long)(a); --i) #define EB emplace_back #define PF push_front #define PB push_back #define MP make_pair #define FI first #define SE second #define ALL(x) x.begin(), x.end() #define COUT(x) cout << #x << " = " << (x) << " (L" << __LINE__ << ")" << endl // input template istream& operator >> (istream &is, vector &P) { for (int i = 0; i < (int)P.size(); ++i) cin >> P[i]; return is; } template istream& operator >> (istream &is, deque &P) { for (int i = 0; i < (int)P.size(); ++i) cin >> P[i]; return is; } template istream& operator >> (istream &is, vector> &P) { for (int i = 0; i < (int)P.size(); ++i) cin >> P[i]; return is; } // output template ostream& operator << (ostream &s, const pair &P) { return s << '<' << P.first << ", " << P.second << '>'; } template ostream& operator << (ostream &s, const array &P) { return s << '<' << P[0] << "," << P[1] << '>'; } template ostream& operator << (ostream &s, const array &P) { return s << '<' << P[0] << "," << P[1] << "," << P[2] << '>'; } template ostream& operator << (ostream &s, const array &P) { return s << '<' << P[0] << "," << P[1] << "," << P[2] << "," << P[3] << '>'; } template ostream& operator << (ostream &s, const vector &P) { for (int i = 0; i < P.size(); ++i) { if (i > 0) { s << " "; } s << P[i]; } return s; } template ostream& operator << (ostream &s, const deque &P) { for (int i = 0; i < P.size(); ++i) { if (i > 0) { s << " "; } s << P[i]; } return s; } template ostream& operator << (ostream &s, const vector> &P) { for (int i = 0; i < P.size(); ++i) { s << endl << P[i]; } return s << endl; } template ostream& operator << (ostream &s, const set &P) { for (auto it : P) { s << "<" << it << "> "; } return s; } template ostream& operator << (ostream &s, const multiset &P) { for (auto it : P) { s << "<" << it << "> "; } return s; } template ostream& operator << (ostream &s, const unordered_set &P) { for (auto it : P) { s << "<" << it << "> "; } return s; } template ostream& operator << (ostream &s, const map &P) { for (auto it : P) { s << "<" << it.first << "->" << it.second << "> "; } return s; } template ostream& operator << (ostream &s, const unordered_map &P) { for (auto it : P) { s << "<" << it.first << "->" << it.second << "> "; } return s; } void yes(bool a) { cout << (a ? "yes" : "no") << endl; } void YES(bool a) { cout << (a ? "YES" : "NO") << endl; } void Yes(bool a) { cout << (a ? "Yes" : "No") << endl; } const vector DX = {1, 0, -1, 0, 1, -1, 1, -1}; const vector DY = {0, 1, 0, -1, 1, -1, -1, 1}; // yukicoder No.952 危険な火薬庫 /* 末尾にドアを追加する。 ノード 0, 1, ..., N, N+1 f(i, j) = (S[j-1] - S[i])^2 選ぶドアが k 個 → 区間の個数は、N+1-k */ void yukicoder_952() { int N; cin >> N; vector A(N + 1, 0), S(N + 2, 0); for (int i = 0; i < N; i++) cin >> A[i], S[i + 1] = S[i] + A[i]; auto f = [&](int i, int j) -> long long { return (S[j - 1] - S[i]) * (S[j - 1] - S[i]); }; MongeShortestPathWithDEdges msp; auto res = msp.solve(N + 1, f, N + 1); //COUT(res); for (int k = 1; k <= N; k++) cout << res[N + 1 - k] << endl; } int main() { yukicoder_952(); }