1223D. Sequence Sorting(DP)
题目链接:传送门
思路:
我们假设序列 D = { d 1 , d 2 , d 3 . . . d k } D=\{d_1,d_2,d_3...d_k\} D={d1,d2,d3...dk},序列 M = { x ∣ x = a i & & x ∉ D , i ∈ [ 1 , n ] } M=\{x|x= a_i\&\&x\notin D,i\in[1,n]\} M={x∣x=ai&&x∈/D,i∈[1,n]}。
即序列D是没有移动的数,序列M是向左移动或向右移动的数,我们设 m a x p o s [ x ] maxpos[x] maxpos[x] 和 m i n p o s [ x ] minpos[x] minpos[x] 分别是数 x x x 在序列 a a a 中出现的最大位置下标和最小位置下标。那么序列D和序列M必定满足下列条件
- 对于 D i , D j D_i,D_j Di,Dj,假设 D i < D j D_i<D_j Di<Dj,那么 m i n p o s [ D j ] > m a x p o s [ D i ] minpos[D_j]>maxpos[D_i] minpos[Dj]>maxpos[Di]。(原因:这样序列才能有序且不移动)
- 对于序列M中的任意一个数,满足 M i M_i Mi 不夹在序列D的最大和最小值之间,即 M i > m a x { x ∣ x ∈ D } M_i>max\{x|x\in D\} Mi>max{x∣x∈D}或 M i < m i n { x ∣ x ∈ D } M_i<min\{x|x\in D\} Mi<min{x∣x∈D}成立,即数列D中相邻的两个元素在排序上也是相邻的(原因:因为序列M中的数字向左或向右移动,那么其必定移动到序列D的两侧,又因为最终序列是有序的,则满足上述条件)
因为序列M的长度加序列D的长度之和为元素的种类数,我们现在只需求出序列D最长为多长即可。
我们用 D P [ i ] DP[i] DP[i]表示序列D中最后一个数是排名为 i i i 的数的最大长度,
- 如果 i = 1 , t h a n d p [ i ] = 1 i=1,than~dp[i]=1 i=1,than dp[i]=1,排名为 i i i 的最小出现位置小于排名为 i − 1 i-1 i−1的最大出现位置, t h a n d p [ i ] = 1 than~~dp[i]=1 than dp[i]=1
- 否则 d p [ i ] = d p [ i − 1 ] + 1 dp[i]=dp[i-1]+1 dp[i]=dp[i−1]+1
代码:
#include<bits/stdc++.h>
#define mset(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=3e5+10;
int minp[N],maxp[N];
vector<int> v;
int dp[N];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;++i)
minp[i]=-1;
v.clear();
for(int i=1;i<=n;++i)
{
int x;
scanf("%d",&x);
v.push_back(x);
if(minp[x]==-1) minp[x]=i;
maxp[x]=i;
}
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
int ans=n;
for(int i=0;i<int(v.size());++i)
{
if(i==0||minp[v[i]]<maxp[v[i-1]]) dp[i]=1;
else dp[i]=dp[i-1]+1;
ans=min(ans,int(v.size())-dp[i]);
}
printf("%d\n",ans);
}
// for()
return 0;
}