結果
問題 |
No.3185 Three Abs
|
ユーザー |
![]() |
提出日時 | 2025-06-20 21:55:41 |
言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 502 ms / 2,000 ms |
コード長 | 9,673 bytes |
コンパイル時間 | 1,652 ms |
コンパイル使用メモリ | 146,800 KB |
実行使用メモリ | 16,560 KB |
最終ジャッジ日時 | 2025-06-20 21:55:58 |
合計ジャッジ時間 | 12,757 ms |
ジャッジサーバーID (参考情報) |
judge3 / judge1 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 1 |
other | AC * 30 |
ソースコード
#include <iostream> #include <iomanip> #include <cassert> #include <vector> #include <algorithm> #include <utility> #include <numeric> #include <tuple> #include <ranges> namespace ranges = std::ranges; namespace views = std::views; // #include "Src/Number/IntegerDivision.hpp" // #include "Src/Utility/BinarySearch.hpp" #include <cstdint> #include <cstddef> namespace zawa { using i16 = std::int16_t; using i32 = std::int32_t; using i64 = std::int64_t; using i128 = __int128_t; using u8 = std::uint8_t; using u16 = std::uint16_t; using u32 = std::uint32_t; using u64 = std::uint64_t; using usize = std::size_t; } // namespace zawa #include <iterator> #include <limits> namespace zawa { template <class T> class CompressedSequence { public: static constexpr u32 NotFound = std::numeric_limits<u32>::max(); CompressedSequence() = default; template <class InputIterator> CompressedSequence(InputIterator first, InputIterator last) : comped_(first, last), f_{} { std::sort(comped_.begin(), comped_.end()); comped_.erase(std::unique(comped_.begin(), comped_.end()), comped_.end()); comped_.shrink_to_fit(); f_.reserve(std::distance(first, last)); for (auto it{first} ; it != last ; it++) { f_.emplace_back(std::distance(comped_.begin(), std::lower_bound(comped_.begin(), comped_.end(), *it))); } } CompressedSequence(const std::vector<T>& A) : CompressedSequence(A.begin(), A.end()) {} inline usize size() const noexcept { return comped_.size(); } u32 operator[](const T& v) const { return std::distance(comped_.begin(), std::lower_bound(comped_.begin(), comped_.end(), v)); } u32 upper_bound(const T& v) const { return std::distance(comped_.begin(), std::upper_bound(comped_.begin(), comped_.end(), v)); } u32 find(const T& v) const { u32 i = std::distance(comped_.begin(), std::lower_bound(comped_.begin(), comped_.end(), v)); return i == comped_.size() or comped_[i] != v ? NotFound : i; } bool contains(const T& v) const { u32 i = std::distance(comped_.begin(), std::lower_bound(comped_.begin(), comped_.end(), v)); return i < comped_.size() and comped_[i] == v; } u32 at(const T& v) const { u32 res = find(v); assert(res != NotFound); return res; } inline u32 map(u32 i) const noexcept { assert(i < f_.size()); return f_[i]; } inline T inverse(u32 i) const noexcept { assert(i < size()); return comped_[i]; } inline std::vector<T> comped() const noexcept { return comped_; } private: std::vector<T> comped_; std::vector<u32> f_; }; } // namespace zawa // #include "Src/Sequence/RunLengthEncoding.hpp" // #include "Src/Algebra/Group/AdditiveGroup.hpp" // #include "Src/DataStructure/FenwickTree/FenwickTree.hpp" #include <concepts> namespace zawa { namespace concepts { template <class T> concept Semigroup = requires { typename T::Element; { T::operation(std::declval<typename T::Element>(), std::declval<typename T::Element>()) } -> std::same_as<typename T::Element>; }; } // namespace concepts } // namespace zawa namespace zawa { namespace concepts { template <class T> concept Identitiable = requires { typename T::Element; { T::identity() } -> std::same_as<typename T::Element>; }; template <class T> concept Monoid = Semigroup<T> and Identitiable<T>; } // namespace } // namespace zawa #include <functional> #include <type_traits> #include <ostream> namespace zawa { template <concepts::Monoid Monoid> class SegmentTree { public: using Value = typename Monoid::Element; private: constexpr u32 left(u32 v) const { return v << 1; } constexpr u32 right(u32 v) const { return v << 1 | 1; } constexpr u32 parent(u32 v) const { return v >> 1; } usize n_; std::vector<Value> dat_; public: SegmentTree() = default; SegmentTree(u32 n) : n_{ n }, dat_(n << 1, Monoid::identity()) { assert(n_); } SegmentTree(const std::vector<Value>& dat) : n_{ dat.size() }, dat_(dat.size() << 1, Monoid::identity()) { assert(n_); for (u32 i{} ; i < n_ ; i++) { dat_[i + n_] = dat[i]; } for (u32 i{static_cast<u32>(n_) - 1} ; i ; i--) { dat_[i] = Monoid::operation(dat_[left(i)], dat_[right(i)]); } } Value get(u32 i) const { assert(i < n_); return dat_[i + n_]; } void operation(u32 i, const Value& value) { assert(i < n_); i += n_; dat_[i] = Monoid::operation(dat_[i], value); while (i = parent(i), i) { dat_[i] = Monoid::operation(dat_[left(i)], dat_[right(i)]); } } void set(u32 i, const Value& value) { assert(i < n_); i += n_; dat_[i] = value; while (i = parent(i), i) { dat_[i] = Monoid::operation(dat_[left(i)], dat_[right(i)]); } } Value product(u32 l, u32 r) const { assert(l <= r and r <= n_); Value leftValue{ Monoid::identity() }, rightValue{ Monoid::identity() }; for (l += n_, r += n_ ; l < r ; l = parent(l), r = parent(r)) { if (l & 1) { leftValue = Monoid::operation(leftValue, dat_[l++]); } if (r & 1) { rightValue = Monoid::operation(dat_[--r], rightValue); } } return Monoid::operation(leftValue, rightValue); } template <class Function> u32 maxRight(u32 l, const Function& f) { assert(l < n_); static_assert(std::is_convertible_v<decltype(f), std::function<bool(Value)>>, "maxRight's argument f must be function bool(T)"); assert(f(Monoid::identity())); u32 res{l}, width{1}; Value prod{ Monoid::identity() }; // 現在の見ている頂点の幅をwidthで持つ // 境界がある頂点を含む部分木の根を探す // (折り返す時は必要以上の幅を持つ根になるが、widthを持っているのでオーバーしない) for (l += n_ ; res + width <= n_ ; l = parent(l), width <<= 1) if (l & 1) { if (not f(Monoid::operation(prod, dat_[l]))) break; res += width; prod = Monoid::operation(prod, dat_[l++]); } // 根から下って、境界を発見する while (l = left(l), width >>= 1) { if (res + width <= n_ and f(Monoid::operation(prod, dat_[l]))) { res += width; prod = Monoid::operation(prod, dat_[l++]); } } return res; } template <class Function> u32 minLeft(u32 r, const Function& f) const { assert(r <= n_); static_assert(std::is_convertible_v<decltype(f), std::function<bool(Value)>>, "minLeft's argument f must be function bool(T)"); assert(f(Monoid::identity())); u32 res{r}, width{1}; Value prod{ Monoid::identity() }; for (r += n_ ; res >= width ; r = parent(r), width <<= 1) if (r & 1) { if (not f(Monoid::operation(dat_[r - 1], prod))) break; res -= width; prod = Monoid::operation(prod, dat_[--r]); } while (r = left(r), width >>= 1) { if (res >= width and f(Monoid::operation(dat_[r - 1], prod))) { res -= width; prod = Monoid::operation(dat_[--r], prod); } } return res; } friend std::ostream& operator<<(std::ostream& os, const SegmentTree& st) { for (u32 i{1} ; i < 2 * st.n_ ; i++) { os << st.dat_[i] << (i + 1 == 2 * st.n_ ? "" : " "); } return os; } }; } // namespace zawa // #include "Src/DataStructure/DisjointSetUnion/DisjointSetUnion.hpp" using namespace zawa; // #include "atcoder/modint" // using mint = atcoder::modint998244353; const long long INF = (long long)1e18; struct M { using Element = long long; static Element identity() { return -INF; } static Element operation(Element L, Element R) { return std::max(L, R); } }; int N; long long A[200020]; long long solve() { std::vector<long long> S(N + 1); for (int i = 0 ; i < N ; i++) S[i + 1] = S[i] + A[i]; CompressedSequence<long long> comp{S}; auto ladd = [&](long long v) { return comp.inverse(comp.size() - 1) - v; }; auto radd = [&](long long v) { return v - comp.inverse(0); }; SegmentTree<M> segL(comp.size()), segR(comp.size()); segL.set(comp.at(0LL), ladd(0LL)); segR.set(comp.at(0LL), radd(0LL)); std::vector<long long> dp(N + 1); for (int i = 0 ; i < N ; i++) { const long long l = segL.product(0, comp.at(S[i + 1]) + 1) - ladd(S[i + 1]); const long long r = segR.product(comp.at(S[i + 1]) + 1, comp.size()) - radd(S[i + 1]); dp[i + 1] = std::max(l, r); segL.operation(comp.at(S[i + 1]), std::abs(S[i + 1]) + ladd(S[i + 1])); segR.operation(comp.at(S[i + 1]), std::abs(S[i + 1]) + radd(S[i + 1])); } // for (auto d : dp) std::cout << d << ' '; // std::cout << std::endl; long long ans = 0LL; for (int i = N - 1 ; i >= 0 ; i--) { ans = std::max(ans, dp[i] + std::abs(S[N] - S[i])); } return ans; } int main() { std::cin.tie(nullptr); std::cout.tie(nullptr); std::ios::sync_with_stdio(false); int T; std::cin >> T; while (T--) { std::cin >> N; for (int i = 0 ; i < N ; i++) std::cin >> A[i]; std::cout << solve() << '\n'; } }