Hướng dẫn giải của Bedao Grand Contest 13 - MAXSUM


Chỉ dùng lời giải này khi không có ý tưởng, và đừng copy-paste code từ lời giải này. Hãy tôn trọng người ra đề và người viết lời giải.
Nộp một lời giải chính thức trước khi tự giải là một hành động có thể bị ban.

Nhận xét: luôn tồn tại một cách chọn ~2~ đoạn ~l, r~ không giao nhau và vẫn đạt được kết quả tối ưu.

Như vậy, ta có thể xây dựng các mảng ~minLeft~ và ~minRight~ ý nghĩa:

  • ~minLeft[i]~ là cách chọn ~1~ đoạn ~l, r~ sao cho ~r \leq i~ và tổng các phần tử thuộc đoạn ~l, r~ là nhỏ nhất có thể.

  • ~minRight[i]~ là cách chọn ~1~ đoạn ~l, r~ sao cho ~i \leq l~ và tổng các phần tử thuộc đoạn ~l, r~ là nhỏ nhất có thể.

Đáp án của bài toán là giá trị ~Sum(a) - 2 \times (minLeft[i] + minRight[i + 1])~ lớn nhất với mọi giá trị ~i~ mà ~1 \leq i < n~. Trong đó, ~Sum(a)~ là tổng các phần tử dãy ~a~.

Code mẫu

#include <bits/stdc++.h>

using namespace std;

#define fi first
#define se second
#define For(i, a, b) for (int i=a;i<=b;++i)
#define Ford(i, a, b) for(int i=a;i>=b;--i)

#define cerr cout
#define deb(x) cerr << #x << ": " << x << endl
#define deba(a, x, y) cerr << #a << ": ", printA(a, x, y)
#define enter cerr << endl;
template<class A>
void printA(A a, int l, int r) {
    For(i, l, r) cerr << a[i] << " ";
    cerr << endl;
}

typedef long long ll;
typedef pair<int, int> ii;
typedef array<int, 3> arr;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<ii> vii;

const int N = 2 * 1e5 + 5;



void solve()
{
    int n; cin >> n;
    vi a(n);
    for (int &x : a) cin >> x;
    if (n == 1) {
        cout << a[0];
        return;
    }
    vll minLeft(n), minRight(n);
    ll s = 0, ma = 0;
    for (int i = 0; i < n; ++i) {
        s += a[i];
        minLeft[i] = s - ma;
        if (i) minLeft[i] = min(minLeft[i], minLeft[i - 1]);
        ma = max(ma, s);
    }
    s = 0, ma = 0;
    for (int i = n - 1; i >= 0; --i) {
        s += a[i];
        minRight[i] = s - ma;
        if (i < n - 1) minRight[i] = min(minRight[i], minRight[i + 1]);
        ma = max(ma, s);
    }
    s = 0;
    for (int x : a) s += x;
    ll ans = max({s, s - 2 * minRight[1], s - 2 * minLeft[n - 2]});
    for (int i = 0; i < n - 1; ++i) {
        ans = max(ans, s - 2 * (minLeft[i] + minRight[i + 1]));
    }
    cout << ans;
}

int main()
{
//  freopen(".inp","r",stdin);
//  freopen(".out","w",stdout);

    ios_base::sync_with_stdio(false);
    cin.tie(NULL);cout.tie(NULL);

    solve();

    return 0;
}

Bình luận

Hãy đọc nội quy trước khi bình luận.



  • 1
    thiennhan37  đã bình luận lúc 14, Tháng 11, 2024, 16:42 sửa 4

    bài này hơi ảo vd test: 2 2 -2 chỉ đổi -2 ra kq là 4 (tức làm 1 thao tác) thì mới ac được bài này mà không sai test 8. code mình: https://ideone.com/EjH9T1


  • -3
    TVSown  đã bình luận lúc 28, Tháng 6, 2023, 4:32

    cập nhật minLeft[i] bằng công thức: minLeft[i] = min(min(minLeft[i - 1], minLeft[i - 1] + a[i]), a[i]); cho e hỏi công thức này có đúng kh ạ


    • -2
      nguyene2p  đã bình luận lúc 30, Tháng 6, 2023, 7:17

      ct trên sai rồi nha, để tìm minleft, minright bạn làm giống như bài dãy con liên tiếp có tổng nhỏ nhất là đc.


      • -6
        HotStepBroz  đã bình luận lúc 9, Tháng 7, 2023, 8:06

        Bình luận này đã bị ẩn vì có quá nhiều phản ứng tiêu cực. Nhấn để xem.


        • -6
          TVSown  đã bình luận lúc 14, Tháng 7, 2023, 7:18

          Bình luận này đã bị ẩn vì có quá nhiều phản ứng tiêu cực. Nhấn để xem.


          • -5
            2211khanhdh  đã bình luận lúc 17, Tháng 7, 2023, 16:29

            Bình luận này đã bị ẩn vì có quá nhiều phản ứng tiêu cực. Nhấn để xem.


            • -7
              OrzSeaPosjtive  đã bình luận lúc 18, Tháng 7, 2023, 0:34

              Bình luận này đã bị ẩn vì có quá nhiều phản ứng tiêu cực. Nhấn để xem.


              • 0
                vantien1526  đã bình luận lúc 24, Tháng 8, 2023, 4:09

                xét n = 1 rồi mình vẫn bị sai 1 test 1 ạ