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;
}