結果

問題 No.2950 Max Min Product
ユーザー zawakasuzawakasu
提出日時 2024-10-28 13:17:33
言語 C++17
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 1,561 ms / 3,000 ms
コード長 5,738 bytes
コンパイル時間 1,420 ms
コンパイル使用メモリ 91,396 KB
実行使用メモリ 31,048 KB
最終ジャッジ日時 2024-10-28 13:18:25
合計ジャッジ時間 50,645 ms
ジャッジサーバーID
(参考情報)
judge5 / judge3
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 2 ms
6,820 KB
testcase_01 AC 2 ms
6,820 KB
testcase_02 AC 2 ms
6,816 KB
testcase_03 AC 1,131 ms
22,152 KB
testcase_04 AC 1,157 ms
24,028 KB
testcase_05 AC 1,184 ms
22,720 KB
testcase_06 AC 1,504 ms
30,708 KB
testcase_07 AC 1,473 ms
30,680 KB
testcase_08 AC 1,479 ms
30,736 KB
testcase_09 AC 789 ms
17,264 KB
testcase_10 AC 1,432 ms
27,068 KB
testcase_11 AC 1,158 ms
23,936 KB
testcase_12 AC 1,474 ms
30,576 KB
testcase_13 AC 1,475 ms
30,696 KB
testcase_14 AC 1,473 ms
30,684 KB
testcase_15 AC 1,561 ms
28,984 KB
testcase_16 AC 1,067 ms
21,848 KB
testcase_17 AC 1,205 ms
23,708 KB
testcase_18 AC 1,499 ms
30,684 KB
testcase_19 AC 1,471 ms
30,784 KB
testcase_20 AC 1,485 ms
30,684 KB
testcase_21 AC 939 ms
19,712 KB
testcase_22 AC 1,092 ms
24,160 KB
testcase_23 AC 788 ms
17,716 KB
testcase_24 AC 1,472 ms
31,048 KB
testcase_25 AC 1,456 ms
31,012 KB
testcase_26 AC 1,478 ms
30,956 KB
testcase_27 AC 1,071 ms
21,776 KB
testcase_28 AC 1,521 ms
29,320 KB
testcase_29 AC 1,111 ms
22,696 KB
testcase_30 AC 1,543 ms
30,732 KB
testcase_31 AC 1,512 ms
30,744 KB
testcase_32 AC 1,507 ms
30,764 KB
testcase_33 AC 1,151 ms
23,308 KB
testcase_34 AC 722 ms
16,960 KB
testcase_35 AC 1,107 ms
22,732 KB
testcase_36 AC 1,499 ms
30,500 KB
testcase_37 AC 1,480 ms
30,560 KB
testcase_38 AC 1,505 ms
30,556 KB
testcase_39 AC 2 ms
6,820 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <iostream>
#include <vector>
#include <utility>
#include <optional>
#include <cassert>
#include <stack>

const long long MOD{998244353};

long long norm(long long v) {
    return (v + MOD) % MOD;
}

long long add(long long L, long long R) {
    long long res{norm(L) + norm(R)};
    if (res >= MOD) res -= MOD;
    return res;
}

long long mult(long long L, long long R) {
    return (norm(L) * norm(R)) % MOD;
}
struct VD {
    long long max_sum{}, min_sum{}, prod_sum{};
    int len{};
    VD() = default;
    VD(long long mx, long long mn, long long pr, int l)
        : max_sum{mx}, min_sum{mn}, prod_sum{pr}, len{l} {}
};

struct VM {
    using T = VD;
    static T identity() {
        return VD{};
    }
    static T operation(T L, T R) {
        L.max_sum = add(L.max_sum, R.max_sum);
        L.min_sum = add(L.min_sum, R.min_sum);
        L.prod_sum = add(L.prod_sum, R.prod_sum);
        L.len += R.len;
        return L;
    }
};

struct OM {
    using T = std::pair<std::optional<int>, std::optional<int>>;
    static T identity() {
        return T{ std::nullopt, std::nullopt };
    }
    static T operation(T L, T R) {
        if (R.first) L.first = R.first;
        if (R.second) L.second = R.second;
        return L;
    }
};

VM::T mapping(VM::T v, OM::T o) {
    if (o.first and o.second) {
        v.max_sum = mult(*o.first, v.len);
        v.min_sum = mult(*o.second, v.len);
        v.prod_sum = mult(*o.first, mult(*o.second, v.len));
    }
    else if (o.first) {
        v.max_sum = mult(*o.first, v.len);
        v.prod_sum = mult(*o.first, v.min_sum);
    }
    else if (o.second) {
        v.min_sum = mult(*o.second, v.len);
        v.prod_sum = mult(*o.second, v.max_sum);
    }
    return v;
}

struct LazySegmentTree {
    using V = VM::T;
    using O = OM::T;
    static int parent(int v) {
        return v >>= 1;
    }
    static int left(int v) {
        return v << 1;
    }
    static int right(int v) {
        return v << 1 | 1;
    }
    static int depth(int v) {
        return 31 - __builtin_clz(v);
    }
    static int trailingZeros(int v) {
        return __builtin_ctz(v);
    }

    struct Node {
        V v{VM::identity()};
        O o{OM::identity()};
    };

    int n{};
    std::vector<Node> dat;
    static V action(const Node& node) {
        return mapping(node.v, node.o);
    }
    void propagate(int v) {
        dat[left(v)].o = OM::operation(dat[left(v)].o, dat[v].o);
        dat[right(v)].o = OM::operation(dat[right(v)].o, dat[v].o);
        dat[v].o = OM::identity();
    }
    void propagateAncestor(int v) {
        int dep{depth(v)};
        int zeros{trailingZeros(v)};
        for (int d{dep} ; d != zeros ; d--) {
            propagate(v >> d);
        }
    }
    void recalc(int v) {
        dat[v].v = VM::operation(action(dat[left(v)]), action(dat[right(v)]));
    }
    void recalcAncestor(int v) {
        v >>= trailingZeros(v);
        for (v = parent(v) ; v ; v = parent(v)) {
            recalc(v);
        }
    }
    LazySegmentTree() = default;
    LazySegmentTree(const std::vector<V>& A) : n{(int)A.size()}, dat(A.size() << 1) {
        assert(A.size());
        for (int i{} ; i < n ; i++) dat[i + n].v = A[i];
        for (int i{n} ; --i ; ) {
            dat[i].v = VM::operation(dat[left(i)].v, dat[right(i)].v);
        }
    }
    int size() const {
        return n;
    }
    void operation(int L, int R, const O& o) {
        assert(0 <= L and L <= R and R <= n);
        L += size();
        R += size();
        propagateAncestor(L);
        propagateAncestor(R);
        for (int l{L}, r{R} ; l < r ; l = parent(l), r = parent(r)) {
            if (l & 1) {
                dat[l].o = OM::operation(dat[l].o, o);
                l++;
            }
            if (r & 1) {
                r--;
                dat[r].o = OM::operation(dat[r].o, o); 
            }
        }
        recalcAncestor(L);
        recalcAncestor(R);
    }
    V product(int L, int R) {
        assert(0 <= L and L <= R and R <= n);
        L += size();
        R += size();
        propagateAncestor(L);
        propagateAncestor(R);
        recalcAncestor(L);
        recalcAncestor(R);
        V l{VM::identity()}, r{VM::identity()};
        for ( ; L < R ; L = parent(L), R = parent(R)) {
            if (L & 1) {
                l = VM::operation(l, action(dat[L]));
                L++;
            }
            if (R & 1) {
                R--;
                r = VM::operation(action(dat[R]), r);
            }
        }
        return VM::operation(l, r);
    }
};

int main() {
    std::cin.tie(nullptr)->sync_with_stdio(false);

    int N;
    std::cin >> N;
    std::vector<int> A(N);
    std::vector<VM::T> init(N);
    for (int i{} ; i < N ; i++) {
        int a;
        std::cin >> a;
        A[i] = a;
        init[i] = VM::T{a, a, (long long)a * a, 1};
    }
    std::vector<int> prevmax(N, -1), prevmin(N, -1);
    {
        std::stack<int> stack;
        for (int i{} ; i < N ; i++) {
            while (stack.size() and A[stack.top()] < A[i]) stack.pop();
            prevmax[i] = stack.size() ? stack.top() : -1;
            stack.push(i);
        }
    }
    {
        std::stack<int> stack;
        for (int i{} ; i < N ; i++) {
            while (stack.size() and A[stack.top()] > A[i]) stack.pop();
            prevmin[i] = stack.size() ? stack.top() : -1;
            stack.push(i);
        }
    }
    LazySegmentTree seg{init};
    long long ans{};
    for (int i{} ; i < N ; i++) {
        seg.operation(prevmax[i] + 1, i, OM::T{ A[i], std::nullopt }); 
        seg.operation(prevmin[i] + 1, i, OM::T{ std::nullopt, A[i] }); 
        ans = add(ans, seg.product(0, i + 1).prod_sum);
    }
    std::cout << ans << '\n';
}
0