제출 #1369826

#제출 시각아이디문제언어결과실행 시간메모리
1369826LOLOLO수열 (APIO14_sequence)C++20
100 / 100
403 ms81012 KiB
#include <iostream>
#include <vector>
#include <deque>

using namespace std;

typedef long long ll;

const int MAXN = 100005;
const int MAXK = 205;

ll prefix[MAXN];
ll dp[2][MAXN];
int parent[MAXK][MAXN];

struct Line {
    ll m, c;
    int id;
    ll eval(ll x) { return m * x + c; }
};

// Kiểm tra đường thẳng l2 có trở nên vô dụng giữa l1 và l3 không
bool is_bad(Line l1, Line l2, Line l3) {
    // Giao điểm (l1, l2) >= Giao điểm (l2, l3)
    return (double)(l2.c - l1.c) * (l2.m - l3.m) >= (double)(l3.c - l2.c) * (l1.m - l2.m);
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    int n, k;
    cin >> n >> k;

    for (int i = 1; i <= n; i++) {
        ll a;
        cin >> a;
        prefix[i] = prefix[i - 1] + a;
    }

    int cur = 1, prev = 0;
    for (int i = 1; i <= k; i++) {
        deque<Line> dq;
        // Đường thẳng khởi tạo từ trạng thái trước đó
        // Với i=1, dp[prev][0] = 0, prefix[0] = 0
        dq.push_back({prefix[i - 1], dp[prev][i - 1] - prefix[i - 1] * prefix[i - 1], i - 1});

        for (int j = i; j <= n; j++) {
            // Tìm đường thẳng tối ưu nhất cho x = prefix[j]
            while (dq.size() >= 2 && dq[0].eval(prefix[j]) <= dq[1].eval(prefix[j])) {
                dq.pop_front();
            }

            dp[cur][j] = dq[0].eval(prefix[j]);
            parent[i][j] = dq[0].id;

            // Thêm đường thẳng mới vào tập ứng cử viên cho bước sau
            Line newLine = {prefix[j], dp[prev][j] - prefix[j] * prefix[j], j};
            while (dq.size() >= 2 && is_bad(dq[dq.size() - 2], dq.back(), newLine)) {
                dq.pop_back();
            }
            dq.push_back(newLine);
        }
        swap(cur, prev);
    }

    // Xuất kết quả
    cout << dp[prev][n] << "\n";
    
    // Truy vết
    int curr_n = n;
    for (int i = k; i >= 1; i--) {
        curr_n = parent[i][curr_n];
        cout << curr_n << (i == 1 ? "" : " ");
    }
    cout << endl;

    return 0;
}
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…