Advertisement
Dang_Quan_10_Tin

DD HSGHN L9 2022-2023

Jan 12th, 2023 (edited)
757
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 3.65 KB | None | 0 0
  1. // O(nlogn)
  2. // Sử dụng kĩ thuật "Phần tử cuối cùng"
  3. #include <bits/stdc++.h>
  4.  
  5. using namespace std;
  6. using ll = long long;
  7.  
  8. constexpr int N = 1e5 + 5;
  9. int n;
  10. int a[N], b[N];
  11. int cnt[N * 2];
  12. int last[N], uniq[N];
  13.  
  14. void Read()
  15. {
  16.     cin >> n;
  17.     for (int i = 1; i <= n; ++i)
  18.         cin >> a[i];
  19. }
  20.  
  21. ll Cal(const vector<pair<int, int>> &lm, const vector<pair<int, int>> &rm, const int &l, const int &m, const int &r, int a[N])
  22. {
  23.     ll ans = 0;
  24.  
  25.     // Imple kĩ thuật "phần tử cuối cùng"
  26.     // uniq[i] = vị trí j lớn nhất mà a[i..j] gồm toàn các phần tử phân biệt
  27.     // Reset mảng
  28.     for (int i = l; i <= r; ++i)
  29.         last[a[i]] = 0;
  30.  
  31.     for (int i = r, minn = r; i >= l; --i)
  32.     {
  33.         if (last[a[i]] != 0)
  34.             minn = min(minn, last[a[i]] - 1);
  35.         last[a[i]] = i;
  36.         uniq[i] = minn;
  37.     }
  38.  
  39.     // Maximum and minimum is in a[l..m]
  40.     for (int i = 0, H = 0; i < lm.size(); ++i)
  41.     {
  42.         while (H < rm.size() && rm[H].first > lm[i].first && rm[H].second < lm[i].second)
  43.             ++H;
  44.         if (uniq[m - i] - (m - i) >= lm[i].second - lm[i].first && lm[i].second - lm[i].first >= (m + 1) - (m - i)) // Đoạn này cần có các phần tử phân biệt
  45.             if (H > 0 && H + i >= lm[i].second - lm[i].first)                                                       // Đoạn này cần có rm.first > lm[i].first và rm.second < lm[i].second
  46.                 ++ans;
  47.     }
  48.  
  49.     // Minimum in a[l..m] and maximum in a[m+1..r]
  50.     // Ta duy trì cnt[v] là số lượng j có max[m+1..j]-j = v, do v có thể < 0 nên cộng thêm N vào
  51.     // Reset mảng đếm
  52.     for (int i = 0; i < lm.size(); ++i)
  53.         cnt[lm[i].first - (m - i) + N] = 0;
  54.  
  55.     for (int i = 0, L = 0, R = 0; i < lm.size(); ++i)
  56.     {
  57.         if (L > uniq[m - i] - (m + 1)) // Đoạn "ứng viên" chắc chắn chứa phần tử trùng
  58.             break;
  59.  
  60.         while (R < rm.size() && R - 1 <= uniq[m - i] - (m + 1) && rm[R].first > lm[i].first)
  61.         {
  62.             ++cnt[rm[R].second - (R + m + 1) + N];
  63.             ++R;
  64.         }
  65.  
  66.         while (R - 1 > uniq[m - i] - (m + 1)) // Lùi biên phải của đoạn "ứng viên" để không chứa phần tử trùng
  67.         {
  68.             --R;
  69.             --cnt[rm[R].second - (R + m + 1) + N];
  70.         }
  71.  
  72.         while (L < R && rm[L].second <= lm[i].second)
  73.         {
  74.             --cnt[rm[L].second - (L + m + 1) + N];
  75.             ++L;
  76.         }
  77.         ans += cnt[lm[i].first - (m - i) + N];
  78.     }
  79.  
  80.     return ans;
  81. }
  82.  
  83. ll DAC(int l, int r)
  84. {
  85.     if (l > r)
  86.         return 0;
  87.     if (l == r)
  88.         return 1;
  89.  
  90.     int m = (l + r) / 2;
  91.     ll ans = DAC(l, m) + DAC(m + 1, r); // Bằng cách này, ta chỉ cần sử dụng một mảng đếm trong hàm Cal()
  92.  
  93.     vector<pair<int, int>> lm({{a[m], a[m]}}), rm({{a[m + 1], a[m + 1]}});
  94.  
  95.     // Biểu diễn cặp (minimum, maximum) dưới dạng pair
  96.     // first -> minimum
  97.     // second -> maximum
  98.  
  99.     for (int i = m - 1; i >= l; --i)
  100.         lm.emplace_back(min(a[i], lm.back().first), max(a[i], lm.back().second));
  101.     for (int i = m + 2; i <= r; ++i)
  102.         rm.emplace_back(min(a[i], rm.back().first), max(a[i], rm.back().second));
  103.  
  104.     // Đảo ngược dãy <=> swap(lm, rm) và i = n - i + 1
  105.     return ans + Cal(lm, rm, l, m, r, a) + Cal(rm, lm, n - r + 1, n - (m + 1) + 1, n - l + 1, b);
  106. }
  107.  
  108. void Solve()
  109. {
  110.     // b là reverse của a
  111.     for (int i = 1; i <= n; ++i)
  112.         b[i] = a[n - i + 1];
  113.  
  114.     cout << DAC(1, n);
  115. }
  116.  
  117. int32_t main()
  118. {
  119.     ios::sync_with_stdio(0);
  120.     cin.tie(0);
  121.     cout.tie(0);
  122.     Read();
  123.     Solve();
  124. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement