题解:World Tour Finals 2025 Algorithm_a LIS Keeping Swaps
chenxi2009 · · 题解
思路
好像有些困难,不妨考虑一下什么时候可以交换
令
我们考虑一个
然后除去开头这些元素之后剩下的元素是一个
我们观察第一组样例,发现上面推导的问题所在:
对于这个更宽松的问题,我们可以贪心地考虑当前序列中剩下的最小元素
继续考虑后续子问题,发现可以归纳为以下几步:
- 从
\text{mxl} 到1 遍历len ; - 将所有
f_i=len 的未加入答案的元素按照从左往右的顺序加入答案; - 如果未加入答案的最小的
P_i 小于目前答案序列的最后一个元素,那么将其加入答案序列。
时间复杂度
代码
#include<bits/stdc++.h>
using namespace std;
#define ep emplace
#define eb emplace_back
#define ef emplace_front
#define ll long long
const int N = 300000;
int T,n,p[N],f[N],mxl,ans[N],ed,it;
pair<int,int> pr[N];
set<int>s;
int main(){
cin.tie(0)->sync_with_stdio(0);
cin >> T;
while(T --){
cin >> n;
for(int i = 1;i <= n;i ++) cin >> p[i];
for(int i = 1;i <= n;i ++) f[i] = 0,s.ep(i);
f[0] = 1e9,mxl = ed = 0,it = 1;
for(int i = n;i;i --){
int l = 0,r = n - i;
while(l < r){
int mid = l + r + 1 >> 1;
if(p[i] < f[mid]) l = mid;
else r = mid - 1;
}
f[l + 1] = max(f[l + 1],p[i]),pr[i] = {l + 1,p[i]};
mxl = max(mxl,l + 1);
}
sort(pr + 1,pr + n + 1),reverse(pr + 1,pr + n + 1);
for(int i = mxl;i;i --){
while(it <= n && pr[it].first >= i){
int num = pr[it ++].second;
if(!s.count(num)) continue;
ans[++ ed] = num;
s.erase(num);
}
if(s.size() && *s.begin() < ans[ed]){
ans[++ ed] = *s.begin();
s.erase(s.begin());
}
}
for(int i = 1;i <= n;i ++) printf("%d ",ans[i]);
printf("\n");
}
return 0;
}