题意

给出一个长度为\(n\)的数组\(a\),每次操作能将一个数移动到数组的首位或末尾,问最少经过多少次操作能将这个数组变成单调不降的。

分析

\(F_1\)中数组\(a\)的每个数字互不相同,我们发现只要找到最长的连续上升子序列(连续指在数组排序后两个数字是相邻的),n减去它的长度\(len\)即为答案,因为这个序列是有序的,只需要\(n-len\)次操作将其他位置的数移动到这个序列的两边使数组整体有序即可。

\(F_2\)中数组\(a\)中可能会有相同的数字,我们可以用近似的方式去做,找到一个最长的连续不降子序列且除了首尾的数字,和序列中的其他数字相同的数字都要在这个子序列中,这样就能保证只用\(n-len\)次操作将其他位置的数移动到这个序列的两边使数组整体有序。

例如序列\(1,2,3,2,4,3\),我们能找到\(1,2,2,3\)这个符合要求的最长连续不降子序列,但是不能选择\(1,2,3,4\)这个子序列,因为不能把剩下的2和3移动到这个序列的两边,而选择\(1,2,2,3\)这个子序列,你可以将剩下的3和4依次移动到数组的末尾。

\(dp\)找到一个最长的符合条件的子序列即可。

Code

#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<sstream>
#include<cstdio>
#include<string>
#include<vector>
#include<bitset>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define rep(i,x,n) for(int i=x;i<=n;i++)
#define per(i,n,x) for(int i=n;i>=x;i--)
#define sz(a) int(a.size())
#define rson mid+1,r,p<<1|1
#define pii pair<int,int>
#define lson l,mid,p<<1
#define ll long long
#define pb push_back
#define mp make_pair
#define se second
#define fi first
using namespace std;
const double eps=1e-8;
const int mod=1e9+7;
const int N=2e5+10;
const int inf=1e9;
int t,n,a[N],b[N],f[N],l[N],r[N],cnt[N],c[N];
int main(){
	ios::sync_with_stdio(false);
	//freopen("in","r",stdin);
	cin>>t;
	rep(cas,1,t){
		cin>>n;
		rep(i,1,n){
			cin>>a[i];
			b[i]=a[i];
			f[i]=cnt[i]=c[i]=0;
			l[i]=inf;
		}
		sort(b+1,b+n+1);
		int m=unique(b+1,b+n+1)-b-1;
		rep(i,1,n){
			a[i]=lower_bound(b+1,b+m+1,a[i])-b;
			l[a[i]]=min(l[a[i]],i);
			r[a[i]]=i;
			c[a[i]]++;
		}
		int ans=0;
		rep(i,1,n){
			int tmp=0;
			if(l[a[i]]==i&&r[a[i]-1]<i) tmp=max(tmp,f[a[i]-1]+1);
			if(l[a[i]]==i) tmp=max(tmp,cnt[a[i]-1]+1);
			tmp=max(tmp,f[a[i]]+1);
			f[a[i]]=tmp;
			if(r[a[i]-1]<i){
				tmp=max(tmp,f[a[i]-1]+c[a[i]]);
				ans=max(ans,tmp);
			}else{
				ans=max(ans,cnt[a[i]-1]+c[a[i]]);
			}
			cnt[a[i]]++;
			c[a[i]]--;
		}
		cout<<n-ans<<'\n';
	}
	return 0;
}