分析题目发现如果把某个数 $x$ 往左移,那么之后所有小于 $x$ 的数也都要往左移
如果把 $x$ 往右移,那么之后所有大于 $x$ 的数也都要往右移
考虑我们首先一定有一个操作 $n$ 次的合法方案
但是发现其实有些数可以不用操作,只要把比它小的和比它大的搞成合法就行了
发现其实不用操作的数的排名一定是连续的一段,证明可以这样考虑
假设排名不是连续的一段,那么两段中间一定有一个数 $x$ 要操作,那么所有大于 $x$ 数或者小于 $x$ 的数一定要操作
那么矛盾,证明完成
那么现在只考虑排名连续的数最长不用操作的值的数量
显然只要这些数出现的最左边和最右边的区间互不相交那么一定可以不用操作
并且一旦相交就必须操作,所以直接从左到右枚举即可
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
inline int read()
{
int x=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
return x*f;
}
const int N=3e5+7;
int Q,n,a[N],L[N],R[N];
int main()
{
Q=read();
while(Q--)
{
n=read();
for(int i=1;i<=n;i++) L[i]=N,R[i]=0;
for(int i=1;i<=n;i++)
a[i]=read(),L[a[i]]=min(L[a[i]],i),R[a[i]]=max(R[a[i]],i);
int cnt=0,now=0,las=0,mx=0;
for(int i=1;i<=n;i++)
{
if(L[i]>n) continue;
cnt++;
now= (!now) ? 1 : (L[i]>las ? now+1 : 1);
las=R[i]; mx=max(mx,now);
}
printf("%d\n",cnt-mx);
}
return 0;
}
来源:oschina
链接:https://my.oschina.net/u/4380903/blog/3378738