---
# System prepended metadata

title: '[Solution] Bài tập 3/3/2023'

---

# [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;
}
```
:::
