题意
有一个1~n的排列,有以下两种操作:
- Drop-2:将倒数第二个数放到开头,前面的数向后平移
- Invert:将倒数第二个数放到开头,前面的数向后平移
若干连续的Drop-2称为Multi-drop。
计算要使该排列排成1~n所需的最少的Multi-drop的数量。
做法
首先Invert可以无条件使用,那么就可以想到使用Multi-drop相当于将一个数字移动到想移到的地方,如下演示:
4 1 2 3 5 6
Invert
⇒
\Rightarrow
⇒ 1 2 3 5 6 4
Drop-2
∗
*
∗ 4
⇒
\Rightarrow
⇒ 5 6 1 2 3 4
Invert
⇒
\Rightarrow
⇒ 1 2 3 4 5 6
以此类推。
所以所求即为需要移动的最少的数字,也就是n-最长不下降子序列长度。
由于Invert操作,需要求n种排列中最大的最长不下降子序列长度。
时间复杂度
O
(
n
3
)
O(n^3)
O(n3)或
O
(
n
2
l
o
g
n
)
O(n^2logn)
O(n2logn)
#include<bits/stdc++.h>
using namespace std;
int n;
int a[600];
int dp[600];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",a+i);
int ans=0;
for(int it=1;it<=n;it++){
int t=a[1];
for(int i=1;i<n;i++) a[i]=a[i+1]; a[n]=t;
memset(dp,0,sizeof(dp));
dp[n]=1;
for(int i=n-1;i;i--){
for(int j=i+1;j<=n;j++){
if(a[i]<a[j]) dp[i]=max(dp[j],dp[i]);
}
dp[i]++;
}
int maxx=0;
for(int i=1;i<=n;i++) maxx=max(maxx,dp[i]);
ans=max(ans,maxx);
}
printf("%d",n-ans);
return 0;
}