# 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' ,'Rời rạc hóa' ,'Hash'.
###### 🛠 Work: At least 14 hours
###### 👤 Writter:@LeThanhMinh
###### 👥 Contributor: [@Editorial-Slayers Team](https://hackmd.io/@Editorial-Slayers)
###### 📋 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 $prefix$ cộng dồn bằng việc khi xét tới $i$ ta có tổng từ $1$ đến $i$ là $prefix[i]$ việc tìm dãy con liên tiêp có tổng lớn nhất từ $1$ đến $i$ chỉ đơn giản là $max(prefix[i] - min(prefix[j]))$ $(1<=j<i<=n)$
* Vậy còn điều kiện $a[i]$ và $a[j]$ bằng nhau thì sao ?
* Ta có thể dùng một mảng $minprefix[k]$ lưu $min$ của các tổng tiền tố $prefix[i]$ có giá trị $a[i] = k$.
--> vậy ta với mỗi $prefix[i]$ ta có thể tìm dãy con liên tiếp có tổng lớn nhất bằng cách trừ đi cho $minprefix[a[i]]$ thỏa mãn với điều kiện đề bài nhưng trước đó phải có một giá trị bằng với $a[i]$ đảm bảo có phần tử đầu bằng với $a[i]$.
___
## Nhận xét
* Việc dùng mảng lưu $min$ của tổng tiền tố có phần tử cuối cùng là $a[i]$ là việc không thể ,vì $|a[i]|<=10^{9}$ nên mảng phải có chỉ số âm hoặc có độ dài $10^{9}$ là điều không thể .**Nhưng** đề bài lại cho $1<= n <= 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ị .Về việc này bạn 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) sort lại dùng struct (c++) vừa lưu giá trị hiện tại vừa lưu vị trí ta có các số sau khi rời rạc đi chỉ có dạng là 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) việc dùng như vậy là quá cồng kềnh nên ta có thể dùng cấu trúc dữ liệu [map](https://codelearn.io/sharing/cau-truc-du-lieu-than-thanh-mang-ten-map) để thay thế :+1:
____
## Code Hướng dẫn
>[color=red] Đừng copy-paste từ lời giải này lời giải này chỉ mang tính chất tham khảo . **Nên nhớ lời nói này là tốt cho bản thân của bạn**
:::success
:::spoiler code
### Solve
``` cpp
const long long INF = 1e18 +7;
const long long MAXN = 1e6 +7; // nên lưu như vậy tránh trường hợp tràn mảng
map<long long , long long > minprefix;
map<long long , bool> check;
long long prefix[MAXN] , a[MAXN];
int main(){
for(int i = 1; i<=n ; i++){
cin>>a[i] ;
}
minprefix[a[1]] = a[1];
check[a[1]] =true;
prefix[1] = a[1];
for(int i = 2 ; i <= n ; i++){
prefix[i] = prefix[i-1] + a[i]; // tính tổng các dãy con liên tiếp từ 1 đến i
// kiểm tra xem đã có L = a[i] hay không
if(check[a[i]] == true){
res = max(res,prefix[i] - minprefix[a[i]] + a[i]); // thao tác cập nhật kết quả
minprefix[a[i]] = (minprefix[a[i]] , prefix[i]);// cập nhật giá trị bé nhất
}
// nếu không có một L = a[i] nào thì ta bắt đầu khởi gán
if(check[a[i]] == false){
minprefix[a[i]] = prefix[i];
check[a[i]] =true;// xác nhận đã có một L thỏa mãn L= a[i]
}
}
cout<<res;
}
```