题意:
给定数组a[n],用两种操作:
1.将数组中所有值为x的数移至开头
2.将数组中所有值为x的数移至末尾
问,经过最少多少次操作,能将数组a[n]变为非递减的有序数列?
(1<=n<=3e5,1<=a[i]<=n)
思路:
如果一个数全部分布在一段连续的区间上,那么可以不移动这个数。如果有好几个这样的连续的连续区间,且它们都是非递减的,那么这一个大区间内的数都可以不移动。因此只要求出最大的(所含数种类最多的)大区间,就能得到答案(只移动剩余的数)。
将所有数离散化之后,记录每个数的最大下标和最小下标,之后实际上是一个最长上升子序列问题。
#include <bits/stdc++.h>
using namespace std;
const int maxn=3e5+5;
int a[maxn],lisan[maxn];
int dp[maxn],max1[maxn],min1[maxn];
int main(){
int q,n;
cin>>q;
while(q--){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
lisan[i]=a[i];
}
sort(lisan+1,lisan+1+n);
int len=unique(lisan+1,lisan+1+n)-(lisan+1);
for(int i=1;i<=n;i++) a[i]=lower_bound(lisan+1,lisan+len+1,a[i])-lisan;
for(int i=1;i<=n;i++){
max1[a[i]]=i;
}
for(int i=n;i>=1;i--){
min1[a[i]]=i;
}
int res=1;
for(int i=1;i<=len;i++)
dp[i]=1;
for(int i=2;i<=len;i++){
if(min1[i]>max1[i-1]){
dp[i]=dp[i-1]+1;
}
res=max(res,dp[i]);
}
int ans=len-res;
printf("%d
",ans);
}
}