# [Solution] Bài tập 3/3/2023 :::info :bulb: Unofficial solution written by sweetestlove. :warning: Thuật toán đúng tuy nhiên code mẫu chưa test kĩ, có thể sai sót. ::: ## Bài 1: Bộ 3 số :book: Thuật toán: Bruteforce Ta nhận thấy $n$ là $1e5$, nếu sử dụng duyệt $3$ lần, tức $O(n^3)$ thì chắc chắn sẽ bị quá thời gian. Tuy nhiên ta để ý giá trị $a_i$ có giá trị tuyệt đối $<=100$, vi thế ta sẽ duyệt trên giá trị của $a_i$ thay vì duyệt theo n. Độ phức tạp: $O(200^3)$ :::spoiler C++ Solution ```c++ #include <bits/stdc++.h> using namespace std; int n, val[205], res=0; int main() { cin >> n; for (int i=1; i<=n; i++) { int x; cin >> x; val[x+100]++; } for (int i=1; i<=200; i++) { for (int j=i+1; j<=200; j++) { for (int k=j+1; k<=200; k++) { if (val[i]!=0 && val[j]!=0 && val[k]!=0 && (i+j+k)%3==0 && val[(i+j+k)/3] != 0 && (i+j+k)/3!=i && (i+j+k)/3!=j && (i+j+k)/3!=k) { //cout << i << ' ' << j << ' ' << k << '\n'; res+=(val[i]*val[j]*val[k]); } } } } cout << res; return 0; } ``` ::: --- ## Bài 2: Tích ba số :book: Thuật toán: Merge sort tree, segment tree. :point_right: Chi tiết thuật toán: Ta để ý bản chất bài toán là tìm số đoạn liên tiếp có kích cỡ là $k+1$ trên khoảng từ $1->n$. Sử dụng cấu trúc sữ liệu merge sort tree (nâng cao của segment tree) để cài đặt, qua đó với mỗi đoạn từ $1$ đến $n-k+1$ ta sẽ lấy 3 số lớn nhất để có tích của chúng là lớn nhất (điều này là hiển nhiên vì tích của 3 số lớn nhất trong một đoạn con chính là tích lớn nhất mà đoạn con đó đạt đuợc). Độ phức tạp: $O(n*(nlog2(k)))$ :::spoiler C++ Solution ```c++ /* * @Author: tsumondai * @Date: 2023-03-01 23:13:00 */ #include <bits/stdc++.h> using namespace std; #define int long long #define fi first #define se second #define pb push_back #define mp make_pair #define foru(i, l, r) for(int i = l; i <= r; i++) #define ford(i, r, l) for(int i = r; i >= l; i--) typedef pair<int, int> ii; typedef pair<ii, int> iii; typedef pair<ii, ii> iiii; const int N = 1e6 + 5; const int oo = 1e9 + 7, mod = 1e9 + 7; int n, m, a[N], k, maxRange[N]; vector<int> arr; void read() { cin >> n >> k; foru(i,0,n-1) cin >> a[i]; k++; } void init() { } namespace subtask23 { vector<int> seg[N]; void build(int ci, int st, int end, pair<int, int>* B) { if (st == end) { seg[ci].push_back(B[st].second); return; } int mid = (st + end) / 2; build(2 * ci + 1, st, mid, B); build(2 * ci + 2, mid + 1, end, B); merge(seg[2 * ci + 1].begin(), seg[2 * ci + 1].end(), seg[2 * ci + 2].begin(), seg[2 * ci + 2].end(), back_inserter(seg[ci])); } int query(int ci, int st, int end, int l, int r, int k) { // Base case if (st == end) return seg[ci][0]; int p = upper_bound(seg[2 * ci + 1].begin(), seg[2 * ci + 1].end(), r) - lower_bound(seg[2 * ci + 1].begin(), seg[2 * ci + 1].end(), l); int mid = (st + end) / 2; if (p >= k) return query(2 * ci + 1, st, mid, l, r, k); else return query(2 * ci + 2, mid + 1, end, l, r, k - p); } void process() { pair<int, int> B[N]; for (int i = 0; i < n; i++) { B[i] = { a[i], i }; } sort(B, B + n); build(0, 0, n - 1, B); int res=-1; foru(i,0,n-k) { res=max(res, a[query(0,0,n-1,i,i+k-1,k)] * a[query(0,0,n-1,i,i+k-1,k-1)] * a[query(0,0,n-1,i,i+k-1,k-2)]); } cout << res; } } signed main() { cin.tie(0)->sync_with_stdio(false); freopen("three.inp", "r", stdin); freopen("three.out", "w", stdout); read(); init(); subtask23::process(); return 0; } ``` :::