結果
| 問題 |
No.952 危険な火薬庫
|
| コンテスト | |
| ユーザー |
nanophoto12
|
| 提出日時 | 2021-12-12 11:01:43 |
| 言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
WA
|
| 実行時間 | - |
| コード長 | 4,232 bytes |
| コンパイル時間 | 4,358 ms |
| コンパイル使用メモリ | 261,792 KB |
| 最終ジャッジ日時 | 2025-01-26 09:02:14 |
|
ジャッジサーバーID (参考情報) |
judge5 / judge2 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 3 |
| other | AC * 5 WA * 18 |
ソースコード
#include <bits/stdc++.h>
#define M_PI 3.14159265358979323846 // pi
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll> P;
typedef tuple<ll, ll, ll> t3;
typedef tuple<ll, ll, ll, ll> t4;
typedef tuple<ll, ll, ll, ll, ll> t5;
#define rep(a,n) for(ll a = 0;a < n;a++)
template<typename T>
static inline void chmin(T& ref, const T value) {
if (ref > value) ref = value;
}
template<typename T>
static inline void chmax(T& ref, const T value) {
if (ref < value) ref = value;
}
#include <atcoder/all>
using namespace atcoder;
typedef modint998244353 mint;
typedef __int128 CHT_TYPE;
class ConvexHullTrickDynamic {
private:
// 直線 **************************************************************
struct Line {
CHT_TYPE a, b; // y = ax + b
mutable std::function<const Line* ()> getSuc; // 次の直線へのポインタ (ソートで用いる)
bool operator<(const Line& rhs) const {
// 取得クエリでは次の直線との差分でソート
if (rhs.b == IS_QUERY) {
const Line* suc = getSuc();
if (suc == nullptr) return false;
const CHT_TYPE& x = rhs.a;
return (suc->a - a) * x + suc->b - b > 0;
}
if (b == IS_QUERY) {
const Line* suc = rhs.getSuc();
if (suc == nullptr) return true;
const CHT_TYPE& x = a;
return (suc->a - rhs.a) * x + suc->b - rhs.b < 0;
}
// 通常の直線どうしは傾きソート
return a < rhs.a;
}
};
// 直線集合 **********************************************************
class LinesSet {
private:
// true -> 最小値クエリ, false -> 最大値クエリ
bool flagMin;
std::multiset<Line> lines;
public:
// コンストラクタ ( 第一引数falseで最大値クエリ,デフォルトで最小値クエリ )
LinesSet(bool flagMin = true) : flagMin(flagMin) {};
// 直線lが不必要であるかどうか
bool isBad(std::multiset<Line>::iterator l) {
const auto&& nel = std::next(l);
if (l == lines.begin()) { // lが傾き最小のとき
if (nel == lines.end()) return false; // lしかないなら必要
return l->a == nel->a && l->b <= nel->b;
}
else {
const auto&& prl = std::prev(l);
if (nel == lines.end()) return l->a == prl->a && l->b <= prl->b;
return (prl->b - l->b) * (nel->a - l->a) >= (nel->b - l->b) * (prl->a - l->a);
}
}
// 直線y=ax+bを追加する
inline void add(CHT_TYPE a, CHT_TYPE b) {
if (flagMin) a = -a, b = -b;
auto&& it = lines.insert(Line{ a, b });
it->getSuc = [=] { return (std::next(it) == lines.end() ? nullptr : &*std::next(it)); };
if (isBad(it)) { lines.erase(it); return; }
while (std::next(it) != lines.end() && isBad(std::next(it))) lines.erase(std::next(it));
while (it != lines.begin() && isBad(std::prev(it))) lines.erase(std::prev(it));
}
// 直線群の中でxの時に最小(最大)となる値を返す
inline CHT_TYPE get(CHT_TYPE x) {
auto&& l = *lines.lower_bound(Line{ x, IS_QUERY });
if (flagMin) return -l.a * x - l.b;
else return l.a * x + l.b;
}
};
static const CHT_TYPE IS_QUERY = std::numeric_limits<CHT_TYPE>::lowest();
LinesSet linesSet;
public:
// コンストラクタ ( 第一引数falseで最大値クエリ,デフォルトで最小値クエリ )
ConvexHullTrickDynamic(bool flagMin = true) : linesSet(flagMin) {}
// 直線y=ax+bを追加する
inline void add(CHT_TYPE a, CHT_TYPE b) { linesSet.add(a, b); }
// あるxのときの直線集合での最小値を求める
inline CHT_TYPE get(CHT_TYPE x) { return linesSet.get(x); }
};
int main() {
ll n;
cin >> n;
vector<ll> as(n);
rep(i, n) cin >> as[i];
vector<CHT_TYPE> ss(n + 1, 0);
rep(i, n) ss[i + 1] = ss[i] + as[i];
vector<vector<CHT_TYPE>> dp(n + 2, vector<CHT_TYPE>(n + 1, 1e15));
dp[0][0] = 0;
for (int i = 0; i < n + 1; i++) {
ConvexHullTrickDynamic cht;
for (int j = 0; j < n + 1; j++) {
if (i + j + 1 > n + 1) continue;
CHT_TYPE a = -2 * ss[i + j];
CHT_TYPE b = ss[i + j] * ss[i + j] + dp[i + j][j];
CHT_TYPE x = ss[i + j];
CHT_TYPE y = ss[i + j] * ss[i + j];
cht.add(a, b);
dp[i + j + 1][j] = cht.get(x) + y;
}
}
for (int k = 1; k <= n; k++) {
cout << (ll)dp[n + 1][k] << endl;
}
return 0;
}
nanophoto12