CF1241 D Sequence Sorting(离散化+DP)

题意

给定数组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);
    }
}
原文地址:https://www.cnblogs.com/ucprer/p/11685518.html