LIS(思维题) - Drop Voicing - 2020牛客暑期多校训练营(第五场)

LIS(思维题) - Drop Voicing - 2020牛客暑期多校训练营(第五场)

题意:

n ( n [ 1 , n ] ) 给定一个长度为n的排列(n个整数都介于[1,n],且不重复),允许两种操作:

D r o p 2 ①、Drop-2:将倒数第二个数放到开头。

I n v e r t ②、Invert:将开头的第一个数放到最后。

每次操作允许选择①或②连续进行多次,

( ) 求最少需要进行几次①操作(每次可以连续多次将倒数第二个数放到开头),

( 1 n ) 可将排列排好序(从1到n递增)。

示例1
输入:

6
2 4 5 1 3 6

输出

2

说明

An optimal solution with two multi-drops is:

  • Invert, 5 times, changing the permutation to 6,2,4,5,1,3;
  • Drop-2, 3 times, changing the permutation to 4,5,1,6,2,3;
  • Invert, 4 times, changing the permutation to 2,3,4,5,1,6;
  • Drop-2, 1 time, changing the permutation to 1,2,3,4,5,6.

示例2
输入

8
8 4 7 3 6 2 5 1

输出

5

分析:

观察操作①和操作②,我们不妨将整个排列看作是一个环。

p k , p k + 1 , . . . , p n 1 我们分析操作①,即每次可以将连续的某一段数p_{k},p_{k+1},...,p_{n-1}逆序后移动到开头,

在环上相当于将这一段逆时针旋转移动到开头,

p k , p k + 1 , . . . , p n 1 p n p 1 , p 2 , . . . , p k 1 也就是说,p_{k},p_{k+1},...,p_{n-1}相对于p_n逆时针移动到了p_1,p_2,...,p_{k-1}这一段的前面,

p n 等价于将p_n移动到了环上的某个位置上。

因此操作①可归纳为:将序列中的任意一个数移动到任意位置上。

分析操作②,我们发现环上任意两数之间的相对位置不改变,因此,操作②对排序无作用。

所以,要求连续进行操作①的最少次数,我们需要找到序列上的最长上升子序列,

n 在最长上升子序列中插入其他的数,最终答案即序列长度n-环上最长上升子序列的长度。

具体做法:

1 n i i D P m a x l n m a x l 从1到n枚举环的起点i,对每个起点i求一遍最长上升子序列的DP,保存最大值maxl,输出n-maxl。

时间复杂度: O ( n 3 ) O(n^3)

代码:

#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>

using namespace std;

const int N=510;

int n,a[N<<1];
int f[N<<1];

int main()
{
    cin>>n;
    for(int i=1;i<=n;i++) 
    {
        cin>>a[i];
        a[n+i]=a[i];
    }
    
    int maxl=0;
    for(int i=1;i<=n;i++)
        for(int j=i;j<=i+n-1;j++)
        {
            f[j]=1;
            for(int k=i;k<j;k++)
                if(a[k]<a[j])
                    f[j]=max(f[j],f[k]+1);
            maxl=max(maxl,f[j]);
        }
    
    cout<<n-maxl<<endl;
        
    return 0;
}

猜你喜欢

转载自blog.csdn.net/njuptACMcxk/article/details/107601282