Advertisement
erek1e

IOI '08 P3 - Fish

Mar 5th, 2023
538
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.00 KB | None | 0 0
  1. #include <iostream>
  2. #include <vector>
  3. #include <algorithm>
  4. #include <queue>
  5.  
  6. using namespace std;
  7.  
  8. int m;
  9. inline int add(int x, int y) {
  10.     x += y;
  11.     if (x >= m) return x-m;
  12.     return x;
  13. }
  14. inline int mult(int x, int y) {return (long long)x*y%m;}
  15.  
  16. // Segment Tree on Product
  17. vector<short> product; vector<int> leftI, rightI;
  18. inline short getVal(int node) {
  19.     return node >= 0 ? product[node] : 1;
  20. }
  21. inline void createNode() {
  22.     product.push_back(1), leftI.push_back(-1), rightI.push_back(-1);
  23. }
  24. void update(int node, int first, int last, int index, short value) {
  25.     if (first+1 == last) {
  26.         product[node] = value;
  27.         return;
  28.     }
  29.     int mid = (first + last) / 2;
  30.     if (index < mid) {
  31.         if (leftI[node] < 0) leftI[node] = product.size(), createNode();
  32.         update(leftI[node], first, mid, index, value);
  33.     } else {
  34.         if (rightI[node] < 0) rightI[node] = product.size(), createNode();
  35.         update(rightI[node], mid, last, index, value);
  36.     }
  37.     product[node] = mult(getVal(leftI[node]), getVal(rightI[node]));
  38. }
  39. short getProduct(int node, int first, int last, int qFirst, int qLast) {
  40.     if (node < 0 || last <= qFirst || qLast <= first) return 1;
  41.     if (qFirst <= first && last <= qLast) return product[node];
  42.     int mid = (first + last) / 2;
  43.     short l = getProduct(leftI[node], first, mid, qFirst, qLast);
  44.     short r = getProduct(rightI[node], mid, last, qFirst, qLast);
  45.     return mult(l, r);
  46. }
  47.  
  48. int main() {
  49.     int n, k; cin >> n >> k >> m;
  50.     vector<pair<int, int>> fish(n);
  51.     for (auto &[l, g] : fish) cin >> l >> g;
  52.     sort(fish.begin(), fish.end());
  53.    
  54.     vector<pair<int, int>> lastOfType(k);
  55.     vector<vector<int>> nextOfType(1+k);
  56.     for (int i = 0; i < k; ++i) lastOfType[i].second = i+1;
  57.     for (int i = 0; i < n; ++i) lastOfType[fish[i].second-1].first = i;
  58.     for (int i = n-1; i >= 0; --i) nextOfType[fish[i].second].push_back(i);
  59.     sort(lastOfType.begin(), lastOfType.end());
  60.     for (vector<int> &v : nextOfType) {
  61.         v.shrink_to_fit();
  62.         vector<int> temp{v.begin(), v.end()};
  63.         swap(temp, v);
  64.     }
  65.  
  66.     vector<int> typeIDsorted(1+k);
  67.     for (int i = 0; i < k; ++i) typeIDsorted[lastOfType[i].second] = i;
  68.  
  69.     vector<int> eatEnd(n); // exclusive
  70.     eatEnd[0] = 0;
  71.     for (int i = 1; i < n; ++i) {
  72.         eatEnd[i] = eatEnd[i-1];
  73.         while (eatEnd[i] < n && 2*fish[eatEnd[i]].first <= fish[i].first) ++eatEnd[i];
  74.     }
  75.  
  76.     // Go through all last of types
  77.     vector<int> cntSoFar(1+k);
  78.     int root = 0; // segment tree of range products over cntSoFar+1
  79.     createNode();
  80.     int curEatEnd = 0; // exclusive
  81.     int combinations = 0;
  82.     for (int id = 0; id < k; ++id) {
  83.         auto [pos, type] = lastOfType[id];
  84.         while (curEatEnd < eatEnd[pos]) {
  85.             int g = fish[curEatEnd].second;
  86.             ++cntSoFar[g];
  87.             update(root, 0, k, typeIDsorted[g], (cntSoFar[g]+1)%m);
  88.             nextOfType[g].pop_back();
  89.             ++curEatEnd;
  90.         }
  91.  
  92.         // find first in eatEnd that can eat nextOfType[type]
  93.         int nxt = (nextOfType[type].empty() ? n : nextOfType[type].back());
  94.         int left = id, right = k;
  95.         while (left+1 < right) {
  96.             int mid = (left + right) / 2;
  97.             if (eatEnd[lastOfType[mid].first] > nxt) right = mid;
  98.             else left = mid;
  99.         }
  100.         int firstCanEat = right;
  101.  
  102.         // add combinations of gems that will not be counted by future fish
  103.         int beforeType = getProduct(root, 0, k, 0, typeIDsorted[type]); // excluding type
  104.         //  all of type, none of firstCanEat onwards (in order of eatEnd)
  105.         int x = mult(beforeType, getProduct(root, 0, k, typeIDsorted[type]+1, firstCanEat));
  106.         //  not all of type, none of later types (in order of eatEnd)
  107.         int y = mult(beforeType, cntSoFar[type]); // without the +1 (range 1 to cntSoFar, no 0, no cntSoFar+1)
  108.  
  109.         combinations = add(combinations, add(x, y));
  110.     }
  111.     cout << combinations << endl;
  112.     return 0;
  113. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement