# | 제출 시각 | 아이디 | 문제 | 언어 | 결과 | 실행 시간 | 메모리 |
---|---|---|---|---|---|---|---|
1262813 | Canuc80k | 3개의 봉우리 (IOI25_triples) | C++20 | 0 ms | 0 KiB |
#include "bits/stdc++.h"
using namespace std;
using ll = long long;
using ld = long double;
using ull = unsigned long long;
ll res = 0;
void add(ll i, ll j, ll k) {
// cout << "Debug: " << i << ' ' << j << ' ' << k << endl;
res ++;
}
// pack trên giá trị đã nén (0..m-1)
static inline u64 pack_comp(int x, int y, int m) {
return (u64)x * (u64)m + (u64)y;
}
long long countr(const vector<int> &a_orig, const vector<int> &b_orig) {
int n = (int)a_orig.size();
if (n == 0) return 0;
int T = max(1, (int)std::sqrt((double)n));
// --- 1) coordinate compression cho mọi giá trị xuất hiện trong a và b
vector<int> vals;
vals.reserve(2 * n);
for (int v : a_orig) vals.push_back(v);
for (int v : b_orig) vals.push_back(v);
sort(vals.begin(), vals.end());
vals.erase(unique(vals.begin(), vals.end()), vals.end());
int m = (int)vals.size();
// mapping value -> id
unordered_map<int,int> val2id;
val2id.reserve(m * 2);
for (int i = 0; i < m; ++i) val2id[vals[i]] = i;
// arrays đã nén
vector<int> a(n), b(n);
for (int i = 0; i < n; ++i) {
a[i] = val2id.at(a_orig[i]);
b[i] = val2id.at(b_orig[i]);
}
// --- 2) posA: indices i where a[i] == v
vector<vector<int>> posA(m);
for (int i = 0; i < n; ++i) posA[a[i]].push_back(i);
// --- 3) posPair: compress tất cả key (a[i], b[i]) -> danh sách indices
vector<u64> keys(n);
for (int i = 0; i < n; ++i) keys[i] = pack_comp(a[i], b[i], m);
vector<u64> uniq_keys = keys;
sort(uniq_keys.begin(), uniq_keys.end());
uniq_keys.erase(unique(uniq_keys.begin(), uniq_keys.end()), uniq_keys.end());
int K = (int)uniq_keys.size();
vector<vector<int>> posPairById(K);
for (int i = 0; i < n; ++i) {
int id = int(lower_bound(uniq_keys.begin(), uniq_keys.end(), keys[i]) - uniq_keys.begin());
posPairById[id].push_back(i);
}
auto find_key_id = [&](u64 key)->int {
auto it = lower_bound(uniq_keys.begin(), uniq_keys.end(), key);
if (it == uniq_keys.end() || *it != key) return -1;
return int(it - uniq_keys.begin());
};
// --- 4) heavy detection (theo posA size)
vector<int> heavyY;
vector<char> isHeavy(m, 0);
for (int v = 0; v < m; ++v) {
if (!posA[v].empty() && (int)posA[v].size() > T) {
heavyY.push_back(v);
isHeavy[v] = 1;
}
}
ll ans = 0;
// ----- LIGHT
for (int k = 0; k < n; ++k) {
int x = a[k], y = b[k];
if (isHeavy[y]) continue; // xử lý ở HEAVY
const auto &Iy = posA[y];
for (int t = 0; t < (int)Iy.size() && Iy[t] < k; ++t) {
int i = Iy[t];
u64 key = pack_comp(x, b[i], m);
int id = find_key_id(key);
if (id == -1) continue;
const auto &vec = posPairById[id]; // vị trí j với (a[j]=x, b[j]=b[i])
int L = int(upper_bound(vec.begin(), vec.end(), i) - vec.begin());
int R = int(lower_bound(vec.begin(), vec.end(), k) - vec.begin());
ans += (ll)(R - L);
}
}
// ----- HEAVY
for (int y : heavyY) {
vector<int> cntI(m, 0); // cntI[t] = số i đã thấy (i < hiện tại) với a[i]=y và b[i]=t
vector<ll> P(m, 0); // P[x] = số cặp (i, j) đã tạo với i có a[i]=y và j có a[j]=x
for (int t = 0; t < n; ++t) {
if (b[t] == y) {
ans += P[a[t]];
}
P[a[t]] += (ll)cntI[b[t]];
if (a[t] == y) cntI[b[t]]++;
}
}
return ans;
}
long long count_triples(std::vector<int> H) {
res = 0;
// #TH: a[k] max
for (int k = 2; k < H.size(); k ++) {
int i = k - H[k]; if (i < 0 || H[i] >= H[k]) continue; int j1 = k - H[i], j2 = i + H[i];
if (j1 < 0 || H[j1] >= H[k] || H[j1] != j1 - i) j1 = -1;
if (j2 >= k || H[j2] >= H[k] || H[j2] != k - j2) j2 = -1;
if (j1 != -1) add(i, j1, k); if (j2 != -1 && j1 != j2) add(i, j2, k);
}
// #TH: a[i] max
for (int i = 0; i + 2 < H.size(); i ++) {
int k = i + H[i]; if (k >= H.size() || H[k] >= H[i]) continue; int j1 = k - H[k], j2 = i + H[k];
if (j1 < 0 || H[j1] >= H[i] || H[j1] != j1 - i) j1 = -1;
if (j2 >= k || H[j2] >= H[i] || H[j2] != k - j2) j2 = -1;
if (j1 != -1) add(i, j1, k); if (j2 != -1 && j1 != j2) add(i, j2, k);
}
// #TH: a[j] max, j - i = a[i]
for (int i = 0; i + 2 < H.size(); i ++) {
int j = i + H[i]; if (j >= H.size() || H[j] <= H[i]) continue; int k = i + H[j];
if (k >= H.size() || H[k] >= H[j] || k - H[k] != j || k - j == H[i]) k = -1;
if (k != -1) add(i, j, k);
}
// #TH: a[j] max, j - i = a[k]
// for (int i = 0; i + 2 < H.size(); i ++) {
// for (int k = i + H[i] + 1; k < H.size(); k ++) {
// int j = i + H[k]; if (j != k - H[i] || j >= H.size()) continue;
// if (H[i] >= H[j] || H[j] <= H[k] || k - i != H[j] || j >= k) continue;
// // cout << "OKE: " << i << ' ' << j << ' ' << k << endl;
// add(i, j, k);
// }
// }
vector<int> a, b;
for (int i = 0; i < H.size(); i ++) a.push_back(H[i] + i);
for (int i = 0; i < H.size(); i ++) b.push_back(i - H[i]);
// for (int i = 0; i < a.size(); i ++)
// for (int j = i + 1; j < a.size(); j ++)
// for (int k = j + 1; k < a.size(); k ++)
// if (a[i] == b[k] && a[j] == a[k] && b[i] == b[j]) res ++;
res += countr(a, b);
return res;
}
int rand(int l, int r) {
static random_device rd;
static mt19937 gen(rd());
uniform_int_distribution<int> dist(l, r);
return dist(gen);
}
std::vector<int> construct_range(int M, int K) {
vector<int> save; ll attempt = 2e6 / M, val = -1;
while (attempt --) {
vector<int> res;
for (int i = 0; i < M; i ++) res.push_back(rand(1, sqrt(M)));
ll x = count_triples(res);
if (x > val) {val = x; save = res;}
}
return save;
// return {4,3,2,3,1,1,2,3,3,1,2,1,4,3,2,3,1,1,2,3};
}