--- tags: VNOJ, THT, DP, Partial Sum, Prefix Sum, Data Structure, LeThanhMinh, SPyofgame title: 🌱 Lời giải bài Tin học trẻ 2021 - Vòng khu vực - Bảng B - Dãy Số author: Editorial-Slayers Team license: Public domain --- $\Huge \text{🌱 Lời giải bài Tin học trẻ 2021 - Vòng khu vực - Bảng B - Dãy Số}$ > Nếu bạn cảm thấy Edit này chất lượng tiếc gì một upvote và giới thiệu team với mọi người nhé :heart: ###### 🔗 Link: [https://oj.vnoi.info/problem/tht21_kvb_seq](https://oj.vnoi.info/problem/tht21_kvb_seq) ###### 📌 Tags: `Prefix Sum` ,`Data Structures` ###### 🛠 Work: 6+ hours ###### 👤 Writer:@LeThanhMinh ###### 👥 Editor: @SPyofgame ,@eggdacoder2006 ###### 📋 Content: [TOC] ____ ## Ý tưởng :+1: Với việc tìm dãy con liên tiếp có tổng lớn nhất ta có thể dùng mảng tổng tiền tố: - Gọi $p[x]$ là tổng các số từ $a[1]$ đến $a[x]$ - Ta có $p[0] = 0$ và $p[x] = p[x - 1] + a[x]$ - Tính chất: $p[r] - p[l - 1] = a_l + a_{l+1} + \dots + a_r$ Tại mỗi vị trí $i$, ta cần tìm tổng lớn nhất có hai số đầu và cuối bằng nhau $\begin{equation} \begin{split} V_i & = max(a_j + a_{j+1} + \dots + a_i\ |\ a_j = a_i \wedge j < i)\\ & = max(p[i] - p[j - 1]\ |\ a_j = a_i \wedge j < i)\\ & = p[i] - min(p[j - 1]\ |\ a_j = a_i \wedge j < i) \end{split} \end{equation}$ Tới đây thôi ta có thẻ tính kết quả trong $O(n^2)$có thẻ tính kết quả trong $O(n^2)$ ____ ## Tối ưu Đặt $M[x]$ là tổng tiền tố nhỏ nhất xét đến $[i - 1]$ có giá trị $[x]$ - Ta có $V_i = p[i] - M[a[i]]$ - Kết quả bài toán là $res = max(V_i\ |\ 1 \leq i \leq n)$ **Lưu ý:** - Trường hợp số $x$ xuất hiện lần đầu ta không tính kết quả vì đề yêu cầu $L < R$ hay dãy phải có ít nhất hai phần tử ___ ## Nhận xét * Việc dùng mảng lưu $min$ các tổng tiền tố có phần tử kết thúc là $a_i$ là việc không thể $(|a_i| \le 10^{9})$. **Nhưng** đề bài lại cho $1 \le n \le 10^{5}$ nên thật ra ta chỉ cần một mảng lưu nhiều nhất là $10^{5}$ giá trị. Do đó ta có thể dùng [phương pháp rời rạc hóa](https://vnoi.info/wiki/algo/trick/Roi-rac-hoa-va-ung-dung.md), mảng lúc này chỉ gồm các số nguyên dương từ $1$ đến $10^{5}$ hoặc dùng [hash](https://vnoi.info/wiki/algo/data-structures/hash-table.md). * Tuy nhiên các cách trên không giúp ta tăng tốc độ code vì vấn đề hằng số nên ta có thể dùng CTDL [map](https://codelearn.io/sharing/cau-truc-du-lieu-than-thanh-mang-ten-map) để thay thế :+1: ____ ## Code Minh Hoạ > **Time:** $O(n \log n)$ > **Space:** $O(n \log n)$ > **Algo:** Prefix sum , Data Structures. > [color=lightgreen] :::success :::spoiler LeMinhThanh code ### Solve ``` cpp #include<bits/stdc++.h> #define ll long long using namespace std; ll n, a[1000005], pre[1000005]; map<ll, ll> minpre; map<ll, ll> check; int main() { cin >> n; for(int i = 1; i <= n; i++) { cin >> a[i]; pre[i] = pre[i - 1] + a[i]; } ll res = -1e18; minpre[a[1]] = a[1]; check[a[1]] = true; pre[1] = a[1]; for(int i = 2 ; i <= n; i++) { if(check[a[i]]) { res = max(res, pre[i] - minpre[a[i]] + a[i]); minpre[a[i]] = min(minpre[a[i]], pre[i]); } else { minpre[a[i]] = pre[i]; check[a[i]] =true; } } cout << res; } ``` ::: :::success :::spoiler Spyofgame code ``` cpp #include <unordered_map> #include <iostream> using namespace std; template<typename T> void maximize(T &res, const T &val) { if (res < val) res = val; } template<typename T> void minimize(T &res, const T &val) { if (res > val) res = val; } typedef long long ll; const ll LINF = 0x3f3f3f3f3f3f3f3f; const int INF = 0x3f3f3f3f; int n; int main() { ios::sync_with_stdio(NULL); cin.tie(NULL); cin >> n; ll s = 0; ll res = -LINF; unordered_map<int, ll> M; for (int i = 1; i <= n; ++i) { int x; cin >> x; if (M.count(x) == false) { M[x] = s; } else { maximize(res, s - M[x] + x); minimize(M[x], s); } s += x; } cout << res; return 0; } ``` ::: :::success _____ ## Bonus - Bạn có thể giải trong $O(n)$ không ?