【2020牛客多校5:D】Drop Voicing(LIS+推理)

传送门

  • 题目
    给定一个长度为 n ( 2 ≤ n ≤ 500 ) n(2≤n≤500) n(2n500)的排列 a [ 0... n − 1 ] a[0...n-1] a[0...n1],有两种操作:
    1、drop-2:将倒数第二个数移到最前面
    2、invert:将第一个数移到最后面
    且连续的drop-2操作称为multi-drop,问最少需要多少个multi-drop操作,使得此排列为升序(即最终的排列为1,2,…,n)
  • 思路
    称连续的invert操作为multi-invert,可以发现将一个数移到任一位置需要最多1个multi-drop操作和多个multi-invert操作。
    x 1 x 2 x 3 x 4 x 5 x 6 x 7 x_1x_2x_3x_4x_5x_6x_7 x1x2x3x4x5x6x7,现在要把 x 4 x_4 x4移到 x 5 x_5 x5 x 6 x_6 x6之间
    (1)将 x 1 x_1 x1~ x 5 x_5 x5移到后面: x 6 x 7 x 1 x 2 x 3 x 4 x 5 x_6x_7x_1x_2x_3x_4x_5 x6x7x1x2x3x4x5,1次multi-invert
    (2)将 x 6 x_6 x6~ x 3 x_3 x3移到后面: x 4 x 5 x 6 x 7 x 1 x 2 x 3 x_4x_5x_6x_7x_1x_2x_3 x4x5x6x7x1x2x3,1次multi-invert
    (3) x 6 x_6 x6~ x 2 x_2 x2移到前面: x 6 x 7 x 1 x 2 x 4 x 5 x 3 x_6x_7x_1x_2x_4x_5x_3 x6x7x1x2x4x5x3,1次multi-drop
    (4)将 x 6 x_6 x6~ x 7 x_7 x7移到后面: x 1 x 2 x 4 x 5 x 3 x 6 x 7 x_1x_2x_4x_5x_3x_6x_7 x1x2x4x5x3x6x7,1次multi-invert
    考虑排列的LIS,对于不属于LIS的数字,最多使用一次multi-drop,将其移到合适的位置,使得len(LIS)+1,那么答案就是n-len(LIS)。
    由于multi-invert操作的次数不计入答案,每次将原排列的前i个(0≤i≤n-1)个数移到后面,得到n个排列,对于每个排列求LIS,最终的ans=min{n-len(LIS)};
  • ac代码
#include
using namespace std;
const int maxn = 5e2 + 10;
int n;
int dp[maxn];
int a[maxn], b[maxn];
int main()
{
    //freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);
    scanf("%d", &n);
    for(int i = 0; i < n; i++) scanf("%d", &a[i]);
    int ans = INT_MAX;
    for(int k = 0; k < n; k++)
    {
        for(int i = 0; i < n; i++) b[(i+n-1-k+n)%n] = a[i];
        dp[0] = 1;
        for(int i = 1; i < n; i++)
        {
            dp[i] = 1;
            for(int j = 0; j < i; j++)
                if(b[i]>b[j]) dp[i] = max(dp[i], dp[j]+1);
        }
        int lis = 1;
        for(int i = 0; i < n; i++) lis = max(lis, dp[i]);
        ans = min(ans, n-lis);
    }
    printf("%d\n", ans);
    return 0;
}

你可能感兴趣的:(思路是个好东西)