1122 Subsequence

感觉这种题就是很套路的玩意,但是想了好久,还是做题做少了。

从贪心的角度考虑,假设我钦定了要选某个数,我该选哪一个呢?显然选择靠前的肯定不会比靠后的更劣。我们当然要选所有能选的数中最靠前的两个。

使用状压 dp,设 表示已经选择过的数字集合为 时最靠后的已选数位置。我们先预处理出每个数出现的位置,每次转移的时候用二分查找找到最靠前的两个即将添加的数字,往后更新。

#include <algorithm>
#include <array>
#include <bit>
#include <cstddef>
#include <iostream>
#include <iterator>
#include <limits>
#include <unordered_set>
#include <vector>
using namespace std;
istream& fin = cin;
ostream& fout = cout;
using ui = unsigned int;
using uli = unsigned long long int;
using li = long long int;
int main(void) {
  ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
  size_t n;
  fin >> n;
  vector<ui> a(n);
  for (ui& i : a) fin >> i, --i;
  array<vector<size_t>, 20> apr;
  for (size_t i = 0; i < n; ++i) apr[a[i]].emplace_back(i);
  vector<size_t> f(1u << 20, numeric_limits<size_t>::max() / 2);
  f[0] = 0;
  for (size_t b = 0; b < f.size(); ++b)
    for (size_t i = 0; i < 20; ++i)
      if (!((1u << i) & b)) {
        auto it = lower_bound(apr[i].begin(), apr[i].end(), f[b]);
        if (it != apr[i].end() && next(it) != apr[i].end())
          f[(1u << i) | b] = min(f[(1u << i) | b], *next(it) + 1);
      }
  ui ans = 0;
  for (size_t b = 0; b < f.size(); ++b)
    if (f[b] != numeric_limits<size_t>::max() / 2)
      ans = max<ui>(ans, popcount(b));
  fout << ans * 2;
  return 0;
}
posted @ 2024-11-23 07:31  MrPython  阅读(4)  评论(0)    收藏  举报  来源