Submission #1265125

#TimeUsernameProblemLanguageResultExecution timeMemory
1265125Canuc80kTriple Peaks (IOI25_triples)C++20
76.08 / 100
1399 ms44352 KiB
#include "bits/stdc++.h" using namespace std; using ll = long long; using ld = long double; using ull = unsigned long long; ll res = 0; map<string, ll> mm; void add(string type, ll i, ll j, ll k) { // if (type.back() != 'G') return; // mm[type] ++; // cout n << "--Spec: " << type << ' ' << i << ' ' << j << ' ' << k << endl; res ++; } long long countr(const vector<int> &a, const vector<int> &b) { int n = (int)a.size(); int T = max(1, (int)std::sqrt((double)n)); using ll = long long; // posA[v] = các chỉ số i có a[i] = v (tăng dần) unordered_map<int, vector<int>> posA; posA.reserve(n * 2); for (int i = 0; i < n; ++i) posA[a[i]].push_back(i); // posPair[(x,y)] = các chỉ số j có (a[j]=x, b[j]=y) (tăng dần) auto pack = [](int x, int y) -> uint64_t { return ( (uint64_t)(uint32_t)x << 32 ) | (uint32_t)y; }; unordered_map<uint64_t, vector<int>> posPair; posPair.reserve(n * 2); for (int i = 0; i < n; ++i) posPair[pack(a[i], b[i])].push_back(i); // Đánh dấu heavy theo bậc của a=y vector<int> heavyY; heavyY.reserve(posA.size()); unordered_set<int> isHeavy; isHeavy.reserve(posA.size() * 2); for (auto &p : posA) { if ((int)p.second.size() > T) { heavyY.push_back(p.first); isHeavy.insert(p.first); } } ll ans = 0; // ----- LIGHT: xử lý theo k, mỗi lần duyệt ≤ T chỉ số i và đếm j bằng binary search for (int k = 0; k < n; ++k) { int x = a[k], y = b[k]; auto itY = posA.find(y); if (itY == posA.end()) continue; if (isHeavy.find(y) != isHeavy.end()) continue; // y nặng sẽ xử lý ở phần HEAVY const auto &Iy = itY->second; // các i có a[i] = y for (int t = 0; t < (int)Iy.size() && Iy[t] < k; ++t) { int i = Iy[t]; uint64_t key = pack(x, b[i]); auto itPair = posPair.find(key); if (itPair == posPair.end()) continue; const auto &vec = itPair->second; // chỉ số j có (a[j]=x, b[j]=b[i]) // Đếm j trong (i, k): i < j < k 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: quét toàn mảng cho từng y nặng for (int y : heavyY) { // cntI[t] = số i đã thấy (i < hiện tại) với a[i]=y và b[i]=t unordered_map<int, int> cntI; cntI.reserve(T * 4); // P[x] = số cặp (i, j) đã tạo với i có a[i]=y, b[i]=b[j], j có a[j]=x (và i<j) unordered_map<int, long long> P; P.reserve(T * 8); for (int t = 0; t < n; ++t) { // 1) k = t (b[k] = y): cộng số cặp (i, j) có j < k, i < j if (b[t] == y) { auto itP = P.find(a[t]); if (itP != P.end()) ans += itP->second; } // 2) j = t: tạo cặp (i, j) với mọi i trước đó thỏa a[i]=y, b[i]=b[j] P[a[t]] += (long long)cntI[b[t]]; // 3) i = t: thêm i vào kho với a[i]=y 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("A[k] Max: ", i, j1, k); if (j2 != -1 && j1 != j2) add("A[k] Max: ", 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("A[i] Max: ", i, j1, k); if (j2 != -1 && j1 != j2) add("A[i] Max: ", 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("A[j] Ma1: ", 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]) add("A[j] Ma2:G", i, j, k); res += countr(a, b); // for (auto [x, y]: mm) cout << x << ' ' << y << endl; 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 n, int k) { vector<int> H, A, B, G; auto check = [&](ll type) -> void { if (H.back() >= n || H.back() <= 0) { // for (auto x: H) cout << x << ' '; cout << endl; cout << "WTF: " << type << endl; exit(0); } }; const long long AMOUNT = 150; const long long START = 150*151/2-10; long long COUNT = 0; // #STEP 1: Build First Part H.push_back(START); B.push_back(- START); A.push_back(START); G.push_back(A.back()); // #STEP 2: Build The Rest for (int i = 1; i < AMOUNT; i ++) { for (int j = 1; j <= i; j ++) { ll pos = H.size(); B.push_back(B[pos - i]); H.push_back(pos - B[pos - i]); check(2); A.push_back(pos * 2 - B[pos - i]); if (j == 1) G.push_back(A.back()); } ll pos = H.size(); A.push_back(A.back()); H.push_back(A.back() - pos); check(3); B.push_back(pos * 2 - A.back()); } // #STEP 3: HARVEST map<ll, ll> m; COUNT = H.size(); while (H.size() < n) H.push_back(rand(1, 2)); for (int i = 0; i < G.size(); i ++) for (int j = i + 1; j < G.size(); j ++) { ll pos = (G[j] + G[i]) / 2; ll val = (G[j] - G[i]) / 2; if (pos <= n && pos >= COUNT && val > 0 && val < n) { H[pos] = val; m[pos] = val; } } // cout << "Count: " << n - COUNT << endl; // cout << "Get: " << m.size() << endl; // for (auto [l, r]: m) cout << "Spec: " << l << ' ' << r << endl; // cout << "G[] = "; for (auto x: G) cout << x << ' '; cout << endl; // cout << "H[] = "; for (auto x: H) cout << x << ' '; cout << endl; // cout << "A[] = "; for (auto x: A) cout << x << ' '; cout << endl; // cout << "B[] = "; for (auto x: B) cout << x << ' '; cout << endl; return H; }
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...