题解/算法 {F - Useless for LIS}
@LINK: https://atcoder.jp/contests/abc354/tasks/abc354_f
;
求哪些元素可以出现在LIS里
二分求LIS里的DP定义是: DP[I]
表示 长度为I
的LIS 其末尾元素的最小值; 在求LIS的过程中 对于每个元素A[i]
, 我们是求出了一个len
他表示 A[0...i]
里 以A[i]
为结尾的LIS的最长长度 (于是DP记录DP[len] = i
);
我们在DP过程中, 再反向记录一下 即Rec[i] = len
, 表示 以A[i]
为结尾的LIS 最长长度为len
;
最终, 我们逆序遍历整个数组, 维护一个Height[ len]
表示 长度为len
的LIS 其末尾元素的最大值;
对于当前A[i]
, 如果Height[ Rec[i] + 1] > A[i]
则当前可以是答案;
比如[1, 8,9, 2, 3, 4]
, 当到达9
时 此时Height[4]=4, Height[3]=3, [2]=2
, 因为Rec[9] = 3
而Height[4]=4 < 9
所以 9不是答案 他也不能更新Height
;
代码
int N; cin>> N;
vector<int> A(N); for( auto & i : A){ cin>> i;}
vector<int> Rec(N);
//{ ___LIS
auto ___LIS = [&]( int const* _arr, int _length){
for( int i = 0; i < _length; ++i){
...
Rec[i] = len; // 记录
}
return MaxLen;
};
//} ___LIS
auto maLen = ___LIS( A.data(), A.size());
vector<char> ANS( N, 1);
vector<int> Height( N+10, -2e9); // `Height[x]=y` 长度为x的LIS 其末尾元素的最大值;
FORrev_( i, N-1, 0){
if( Rec[i]!=maLen && Height[ Rec[i]+1] <= A[i]){
ANS[i] = 0;
continue; // 注意这里;
}
Height[ Rec[i]] = A[i]; // 这里不用取`max`, 因为他一定是单调的(即每次更新的值 不会比当前小);
}
FOR_( i, 0, N-1){
if( ANS[i]){ cout<< i<< " ";}
}