题目
【codeforce-650F2】 Flying Sort (Hard Version)
DP
使用一种排序加单调队列的dp做法,参考博客,具体做法如下:
代码
class F1{
//CF650F2 Flying Sort (Hard Version) (思维)承接E题,这个相关类型的题目进行练习
public:
void solve(){
//双关键字排序+单调栈寻找最长连续子序列
//key:值域需要连续,有点单调栈的意思
//相同的x值,让index高的在前面,这样把set中不合理的去掉不会影响当前x值中index低的dp规划
//如果排序按照index低的先做决策,有可能会使得index高的时候做决策,有一些解空间被去掉了
//因为我们是要求值域连续,所以当前x的值一定要都保存到set中,供后面的决策,也就是x之前的值被去掉不会影响x值之后的决策
//,x值之后的x+1的值的决策,只取决于当前x值中的最后决策;
//因为要求值连续,所以,不可能存在一段 [x-2,x-2...,x-1,x-1,...,x,x,...] 中间x-1的值不完全包含的情况,
// 这样没法固定使得部分x-1的值无法用过两种操作插入中间,所有x-1在下一个x到来之前,一定要取全部,并且过滤掉前面不合理的值
int t;
cin>>t;
int n;
while(t--){
cin>>n;
vector<ii> a(n);
for(int i=0;i<n;i++) {
cin>>a[i].fi;
a[i].se=i+1;
}
sort(all(a),[](const ii& a,const ii&b){
if(a.fi!=b.fi) return a.fi<b.fi;
else return a.se>b.se;
});
deque<int> mono;//单调队列
stack<int> help;//中间栈,存储值相同的操作
int ans=0;
for(int i=0;i<n;i++){
if(i>0&&a[i].fi!=a[i-1].fi){//把前面的a[i].fi-1的值放到单调栈中
while(!help.empty()) {
mono.push_back(help.top());
help.pop();
}
}
while(!mono.empty()&&a[mono.back()].se>a[i].se) {
//之前的跨度是大于1的要去掉
while(!mono.empty()&&a[mono.front()].fi<a[mono.back()].fi) mono.pop_front();
mono.pop_back();
}
help.push(i);
ans=max(ans,(int)(help.size()+mono.size()));
}
cout<<n-ans<<endl;
}
}
};