CF 1801 C

Yaosicheng124發表於2024-09-15

題目描述

\(N\) 個專輯,第 \(i\) 個專輯中有 \(k_i\) 首歌曲,其中第 \(j\) 首歌的酷炫程度為 \(a_{i,j}\)

你會選擇一個排列 \(p_1,p_2,\dots,p_N\),每次你會將 \(p_i\) 中所有歌曲從前往後依次聽完。每當你遇到一個嚴格大於之前聽過所有歌曲的歌曲,則你會對這個歌曲產生印象。

求最多能有多少個令你產生印象的歌曲。

思路

考慮貪心地求解。

很容易想到這樣一種貪心:按每個專輯的最大值從小到大排序,然後做 dp。

但是不是對的呢?假設我們其中有一個專輯 \(i\) 不是從小到大排序的,即 \(\max\limits_{j=1}^{k_i} \{a_{i,j}\}>\max\limits_{j=1}^{k_{i+1}} \{a_{i+1,j}\}\),那麼此時 \(i,i+1\) 都無法互相轉移。但將 \(i,i+1\) 交換,它才有可能轉移。而多一些轉移一定不會使答案更劣,所以此貪心正確。

dp 使用樹狀陣列最佳化即可。

這裡清空要注意不能每次把整個樹狀陣列清空,而要記錄被修改過的位置進行清空。

空間複雜度 \(O(N+\max \limits_{1\le i\le N,1\le j \le k_i}\{a_{i,j}\} + \sum \limits_{i=1}^N k_i \log \max \limits_{1\le i\le N,1\le j \le k_i}\{a_{i,j}\})\),時間複雜度 \(O(N\log N + \sum \limits_{i=1}^N k_i \log \max \limits_{1\le i\le N,1\le j \le k_i}\{a_{i,j}\})\)

程式碼

#include<bits/stdc++.h>
using namespace std;

const int MAXN = 200001, MAXV = 200002;

int t, n, id[MAXN], Max[MAXN], tr[MAXV];
vector<int> a[MAXN], pos;

int lowbit(int x) {
  return x & -x;
}

void update(int p, int x) {
  p++;
  for(; p < MAXV; tr[p] = max(x, tr[p]), pos.push_back(p), p += lowbit(p)) {
  }
}

int Getmax(int p) {
  p++;
  int Max = 0;
  for(; p; Max = max(Max, tr[p]), p -= lowbit(p)) {
  }
  return Max;
}

void Solve() {
  cin >> n;
  pos.clear();
  for(int i = 1, k; i <= n; ++i) {
    cin >> k;
    id[i] = i;
    Max[i] = 0;
    a[i].clear();
    a[i].resize(k + 1);
    for(int j = 1; j <= k; ++j) {
      cin >> a[i][j];
      Max[i] = max(Max[i], a[i][j]);
    }
  }
  sort(id + 1, id + n + 1, [](const int &a, const int &b) {
    return Max[a] < Max[b];
  });
  for(int i = 1; i <= n; ++i) {
    int maxx = 0, res = 0;
    for(int j = 1; j < int(a[id[i]].size()); ++j) {
      if(a[id[i]][j] > maxx) {
        res = max(res, Getmax(a[id[i]][j] - 1)) + 1;
        maxx = a[id[i]][j];
      }
    }
    update(Max[id[i]], res);
  }
  cout << Getmax(MAXV - 2) << "\n";
  pos.erase(unique(pos.begin(), pos.end()), pos.end());
  for(int x : pos) {
    tr[x] = 0;
  }
}

int main() {
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  for(cin >> t; t--; Solve()) {
  }
  return 0;
}