Hướng dẫn giải của Đánh giá TB
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.
Hướng dẫn giải
Đếm số bộ ba phiếu ~(i, j, k)~ đôi một khác nhau thỏa ~a_i + a_j = 2 \cdot a_k~ (tức ~a_k~ là trung bình cộng của hai điểm kia). Các điểm đôi một khác nhau, mỗi bộ ba (không phân biệt thứ tự hai phiếu ~i, j~) tính một lần.
Lưu ý: ví dụ trong đề (~3\ 1\ 4\ 2\ 5~, đáp án 2) không khớp cách hiểu này (theo đề, các bộ ba là ~\{1,2,3\}, \{2,3,4\}, \{3,4,5\}, \{1,3,5\}~ nên ra 4); toàn bộ 20 test chấm đều khớp cách hiểu này nên ta dùng nó.
Sub 1: Vét cạn — ~O(n^3)~, dùng khi ~n \le 100~
Duyệt mọi bộ ba chỉ số ~i < j < l~, thử lần lượt từng phần tử làm phần tử giữa. Nếu chỉ nộp sub này: đúng 10/20 test.
Sub 2: Hai con trỏ — ~O(n^2)~, dùng khi ~n \le 10^4~
Sắp xếp mảng. Với mỗi ~k~, đếm số cặp có tổng bằng ~2 \cdot a_k~ bằng hai con trỏ ~O(n)~. Vì các giá trị khác nhau nên cặp tìm được không chứa chính ~k~. Nếu chỉ nộp sub này: đúng 20/20 test.
Chương trình hoàn chỉnh
Nếu ~n \le 100~ dùng sub 1, ngược lại dùng sub 2. Khi đi thi nên viết như vậy: sub sau có sai hoặc chưa kịp làm thì vẫn ăn điểm sub trước.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
vector<ll> a;
// Đếm số bộ ba phiếu {i, j, k} (3 chỉ số khác nhau) có a_i + a_j = 2*a_k, mỗi bộ ba tính một lần.
// (Ví dụ trong đề ghi 2 nhưng theo cách hiểu này ra 4; toàn bộ test chấm khớp cách hiểu này.)
// Sub 1: vét cạn O(n^3), dùng khi n <= 100: thử mọi bộ ba chỉ số i < j < l, lần lượt coi từng phần tử là phần tử giữa
void sub1() {
ll ans = 0;
for (int i = 0; i < n; i++)
for (int j = i + 1; j < n; j++)
for (int l = j + 1; l < n; l++) {
if (a[i] + a[j] == 2 * a[l]) ans++;
if (a[i] + a[l] == 2 * a[j]) ans++;
if (a[j] + a[l] == 2 * a[i]) ans++;
}
cout << ans << "\n";
}
// Sub 2: O(n^2): sắp xếp giá trị, với mỗi k dùng hai con trỏ đếm cặp có tổng 2*a_k
// (các giá trị đôi một khác nhau nên cặp tìm được không chứa k, vì a_k + a_k = 2*a_k chỉ khi i = j = k)
void sub2() {
vector<ll> s = a;
sort(s.begin(), s.end());
ll ans = 0;
for (int k = 0; k < n; k++) {
ll t = 2 * a[k];
int lo = 0, hi = n - 1;
while (lo < hi) {
ll sum = s[lo] + s[hi];
if (sum < t) lo++;
else if (sum > t) hi--;
else { ans++; lo++; hi--; }
}
}
cout << ans << "\n";
}
int main() {
cin >> n;
a.resize(n);
for (auto& x : a) cin >> x;
if (n <= 100) sub1();
else sub2();
return 0;
}
Bình luận