Codeforces Round #591 (Div. 2)D. Sequence Sorting(思维+dp)

D. Sequence Sorting

题意:

输入有 q ( 3 e 5 ) q(3e5) q(3e5)组数据
每组数据输入 n ( ∑ n ≤ 3 e 5 ) n(\sum n\leq3e5) n(n3e5)
接下来一行输入 a 1 , a 2 , … , a n ( 1 ≤ a i ≤ n ) a_1,a_2,\dots,a_n(1\leq a_i\leq n) a1,a2,,an(1ain)
一次操作可以把一个数字移动到最左边或最右边,问最少经过几次操作可以使序列变成不下降序列。

题解:

不妨设每个数字只移动一次,把数字离散化,观察序列的有序性。
其实会发现一个性质,连续有序的一部分的数字可以不动,其它的数字要么左移要么右移,因此只要最大化连续有序部分的长度就好了。

代码:

#include
using namespace std;
const int N=3e5+9;
int q,a[N],n,b[N];
bool vis[N];
int f[N];
vector<int>g[N];
int dp[N];
void solve(){
    //memset(dp,0,sizeof(dp));
    sort(b+1,b+n+1);int nb;
    nb=unique(b+1,b+n+1)-b-1;
   // for(int i=1;i<=nb;i++)cout<
    int ans=1;dp[1]=1;
    for(int i=1;i<nb;i++){
        int x=b[i],y=b[i+1];
        if(g[x].back()<g[y][0])dp[i+1]=dp[i]+1;else dp[i+1]=1;
        ans=max(ans,dp[i+1]);
    }
    cout<<nb-ans<<endl;
}
int main(){
 //   freopen("tt.in","r",stdin),freopen("tt.out","w",stdout);
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    cin>>q;
    while(q--){
        cin>>n;
        for(int i=1;i<=n;i++)cin>>a[i],b[i]=a[i],g[a[i]].push_back(i);
        solve();
        for(int i=1;i<=n;i++)g[a[i]].clear();
    }
    return 0;
}

你可能感兴趣的:(思维,dp)