Submission #1039183

#TimeUsernameProblemLanguageResultExecution timeMemory
1039183june0501수열 (APIO14_sequence)C++17
100 / 100
352 ms87788 KiB
#include <bits/stdc++.h>
//#pragma GCC target("avx2")
//#pragma GCC optimize("O3,unroll-loops")
#define fastIO ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define endl '\n'
#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()
using namespace std;
using ll [[maybe_unused]] = long long;
using ull [[maybe_unused]] = unsigned long long;
using lll [[maybe_unused]] = __int128;
using lld [[maybe_unused]] = long double;
using llld [[maybe_unused]] = __float128;
#define GRAPH_TYPE_DEFINED
template<typename T> using graph [[maybe_unused]] = vector<vector<pair<int,T>>>;
#define MATRIX_TYPE_DEFINED
template<typename T> using matrix [[maybe_unused]] = vector<vector<T>>;

/**
 *  "Premature optimization is the root of all evil."
 *  <sub> Donald Knuth </sub>
 */

#ifdef ONLINE_JUDGE // Be careful if problem is about strings.
/**
 * Namespace for Fast I/O
 *
 * @class@b INPUT
 * class which can replace the cin
 *
 * @class@b OUTPUT
 * class which can replace the cout
 *
 * @Description
 * These classes use low-level i/o functions (@c fread()/mmap() for input, @c fwrite()/write() for output)
 * so that they can read or write much faster than cin and cout. <br>
 * Several macros are defined for convenience of using them.
 *
 * @Author  <a href="https://blog.naver.com/jinhan814/222266396476">jinhan814</a>
 * @Date    2021-05-06
 */
namespace FastIO {
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>

    constexpr int SZ = 1 << 20;

    /* Class INPUT */
    class INPUT {
    private:
        char* p;
        bool __END_FLAG__, __GET_LINE_FLAG__; // NOLINT
    public:
        explicit operator bool() const { return !__END_FLAG__; }
        INPUT() {
            struct stat st;
            fstat(0, &st);
            p = (char*)mmap(0, st.st_size, PROT_READ, MAP_SHARED, 0, 0);
        }

        static bool IsBlank(char c) { return c == ' ' || c == '\n'; }

        static bool IsEnd(char c) { return c == '\0'; }

        char _ReadChar() { // NOLINT
            return *p++;
        }

        char ReadChar() {
            char ret = _ReadChar();
            for (; IsBlank(ret); ret = _ReadChar());

            return ret;
        }

        template<class T>
        T ReadInt() {
            T ret = 0;
            char curr = _ReadChar();
            bool minus_flag = false;

            for (; IsBlank(curr); curr = _ReadChar());
            if (curr == '-') minus_flag = true, curr = _ReadChar();
            for (; !IsBlank(curr) && !IsEnd(curr); curr = _ReadChar())
                ret = 10 * ret + (curr & 15);
            if (IsEnd(curr)) __END_FLAG__ = true;

            return minus_flag ? -ret : ret;
        }

        std::string ReadString() {
            std::string ret;
            char curr = _ReadChar();
            for (; IsBlank(curr); curr = _ReadChar());
            for (; !IsBlank(curr) && !IsEnd(curr); curr = _ReadChar())
                ret += curr;
            if (IsEnd(curr)) __END_FLAG__ = true;

            return ret;
        }

        double ReadDouble() {
            std::string ret = ReadString();
            return std::stod(ret);
        }

        std::string getline() {
            std::string ret;
            char curr = _ReadChar();
            for (; curr != '\n' && !IsEnd(curr); curr = _ReadChar())
                ret += curr;
            if (__GET_LINE_FLAG__) __END_FLAG__ = true;
            if (IsEnd(curr)) __GET_LINE_FLAG__ = true;

            return ret;
        }

        friend INPUT &getline(INPUT &in, std::string &s) {
            s = in.getline();
            return in;
        }
    } _in;
    /* End of Class INPUT */

    /* Class OUTPUT */
    class OUTPUT {
    private:
        char writeBuffer[SZ];
        int write_idx;
    public:
        ~OUTPUT() { Flush(); }

        explicit operator bool() const { return true; }

        void Flush() {
            write(1, writeBuffer, write_idx);
            write_idx = 0;
        }

        void WriteChar(char c) {
            if (write_idx == SZ) Flush();
            writeBuffer[write_idx++] = c;
        }

        template<class T>
        void WriteInt(T n) {
            int sz = GetSize(n);
            if (write_idx + sz >= SZ) Flush();
            if (n < 0) writeBuffer[write_idx++] = '-', n = -n;
            for (int i = sz; i-- > 0; n /= 10)
                writeBuffer[write_idx + i] = n % 10 | 48;
            write_idx += sz;
        }

        void WriteString(const std::string& s) {
            for (auto &c: s) WriteChar(c);
        }

        void WriteDouble(double d) {
            WriteString(std::to_string(d));
        }

        template<class T>
        int GetSize(T n) {
            int ret = 1;
            for (n = n >= 0 ? n : -n; n >= 10; n /= 10) ret++;

            return ret;
        }
    } _out;
    /* End of Class OUTPUT */

    /* Operators */
    INPUT &operator>>(INPUT &in, char &i) {
        i = in.ReadChar();
        return in;
    }

    INPUT &operator>>(INPUT &in, std::string &i) {
        i = in.ReadString();
        return in;
    }

    template<class T, typename std::enable_if_t<std::is_arithmetic_v<T>> * = nullptr>
    INPUT &operator>>(INPUT &in, T &i) {
        if constexpr (std::is_floating_point_v<T>) i = in.ReadDouble();
        else if constexpr (std::is_integral_v<T>) i = in.ReadInt<T>();
        return in;
    }

    OUTPUT &operator<<(OUTPUT &out, char i) {
        out.WriteChar(i);
        return out;
    }

    OUTPUT &operator<<(OUTPUT &out, const std::string &i) {
        out.WriteString(i);
        return out;
    }

    template<class T, typename std::enable_if_t<std::is_arithmetic_v<T>> * = nullptr>
    OUTPUT &operator<<(OUTPUT &out, T i) {
        if constexpr (std::is_floating_point_v<T>) out.WriteDouble(i);
        else if constexpr (std::is_integral_v<T>) out.WriteInt(i);
        return out;
    }

    /* Macros for convenience */
    #undef fastIO
    #define fastIO 1
    #define cin _in
    #define cout _out
    #define istream INPUT
    #define ostream OUTPUT
};
using namespace FastIO;
#endif

/**
 * Convex Hull Trick implementation
 * @tparam Comp default to be std::greater which means query gives minimum value
 */
template<typename Comp = std::greater<>>
class ConvexHullTrick {
    Comp comp;

    struct Fraction {
        // a / b
        ll a, b;
        Fraction(ll a, ll b) : a(a), b(b) {
            if (b < 0) a = -a, b = -b;
        }
        Fraction(ll a) : a(a), b(1) {} // NOLINT(implicit conversion)
        bool operator< (const Fraction &other) const {
            return (lll) a * other.b < (lll) b * other.a;
        }
        bool operator== (const Fraction &other) const {
            return (lll) a * other.b == (lll) b * other.a;
        }
        bool operator<= (const Fraction &other) const {
            return (*this == other) || (*this < other);
        }
        bool operator> (const Fraction &other) const {
            return !(*this <= other);
        }
        bool operator>= (const Fraction &other) const {
            return !(*this < other);
        }
    };

    struct Line : public Fraction {
        // f(x) = ax + b
        Line(ll a, ll b) : Fraction(a, b) {}
    };

    [[nodiscard]] // return the value of f(x) = ax + b
    ll get_value(const Line& f, const ll x) const { return f.a * x + f.b; }

    [[nodiscard]] // return the x pos of the intersection of the two given lines
    Fraction get_cross_x(const Line& l1, const Line& l2) const {
        // a1 x + b1 = a2 x + b2 -> (a1 - a2)x = (b2 - b1)
        return {l2.b - l1.b, l1.a - l2.a};
    }

    [[nodiscard]] // return cross_x(l1, l2) > cross_x(l2, l3)
    bool compare_cross(const Line& l1, const Line& l2, const Line& l3) const {
        return get_cross_x(l1, l2) > get_cross_x(l2, l3);
    }

    std::vector<pair<Line,int>> lines; // maintain the hull

public:
    void insert(ll a, ll b, int idx) {
        Line newLine(a, b);
        for (int sz = (int)lines.size(); sz > 1; sz--) {
            if (a == lines.back().first.a && b >= lines.back().first.b
            || compare_cross(lines[sz - 2].first, lines[sz - 1].first, newLine)) lines.pop_back();
            else break;
        }
        lines.emplace_back(newLine, idx);
    }

    pair<ll,int> query(ll x) {
        int l = 0, r = lines.size() - 1;
        while (l != r) {
            int m = (l + r) >> 1;
            if (comp(get_value(lines[m].first, x), get_value(lines[m+1].first, x))) l = m + 1;
            else r = m;
        }
        return {get_value(lines[l].first, x), lines[l].second};
    }

    // only can be used when x is monotonically increasing
    int ptr = 0;
    pair<ll,int> query_monotonic(ll x) {
        while (ptr + 1 < lines.size() && comp(get_value(lines[ptr].first, x), get_value(lines[ptr + 1].first, x))) ptr++;
        return {get_value(lines[ptr].first, x), lines[ptr].second};
    }

    void clear() {
        lines.clear();
        ptr = 0;
    }
};

int32_t main() {
    fastIO;
    int n, K;
    cin >> n >> K;
    vector<ll> v(n + 1, 0);
    for (int i = 1; i <= n; i++) cin >> v[i], v[i] += v[i-1];

    // dp[k][i] := max val when covers 1 to i with k slices
    // dp[k][i] = max_{j < i}(dp[k-1][j] + (prefix[i] - prefix[j]) * prefix[j])
    // Let y(k) = dp[k][i], x = prefix[i],
    // then, y(k) = prefix[j] * x - prefix[j]^2 + dp[k-1][j]

    matrix<ll> dp(2, vector<ll>(n + 1, 0));
    matrix<int> rev(K + 1, vector<int>(n + 1));
    ConvexHullTrick<less_equal<>> CHT;
    for (int k = 1; k <= K; k++) {
        CHT.clear();
        for (int i = 1; i < n; i++) {
            CHT.insert(v[i], dp[0][i] - v[i] * v[i], i);
            tie(dp[1][i + 1], rev[k][i + 1]) = CHT.query_monotonic(v[i+1]);
        }
        swap(dp[0], dp[1]);
    }
    cout << dp[0][n] << endl;

    vector<int> ans;
    for (int k = K, i = n; k > 0; k--) {
        ans.emplace_back(i = rev[k][i]);
    }
    reverse(all(ans));
    for (const auto &e : ans) cout << e << ' ';

    return 0;
}

Compilation message (stderr)

sequence.cpp: In instantiation of 'void ConvexHullTrick<Comp>::insert(ll, ll, int) [with Comp = std::less_equal<void>; ll = long long int]':
sequence.cpp:325:55:   required from here
sequence.cpp:277:43: warning: suggest parentheses around '&&' within '||' [-Wparentheses]
  277 |             if (a == lines.back().first.a && b >= lines.back().first.b
      |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~
sequence.cpp: In instantiation of 'std::pair<long long int, int> ConvexHullTrick<Comp>::query_monotonic(ll) [with Comp = std::less_equal<void>; ll = long long int]':
sequence.cpp:326:74:   required from here
sequence.cpp:297:24: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<std::pair<ConvexHullTrick<std::less_equal<void> >::Line, int>, std::allocator<std::pair<ConvexHullTrick<std::less_equal<void> >::Line, int> > >::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  297 |         while (ptr + 1 < lines.size() && comp(get_value(lines[ptr].first, x), get_value(lines[ptr + 1].first, x))) ptr++;
      |                ~~~~~~~~^~~~~~~~~~~~~~
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...