Statement
- 有两种操作
-
operation−1 取倒数第二个移到首位
-
operation−2 把第一个移到末尾
- 要求多次
operation−1连在一起时次数最小
Solution 1
- 由
operation−2易得这是一个随便转的圆盘
- 而圆盘旋转并不改变元素的相对位置
- 只有
operation−1改变了相对位置
- 当多次执行
operation−1时
- 每一次挪动的时候,其它数字被挤开相应往顺时针挪动
- 看上去很复杂
- 我们把移动的所有数字
ax...an−1看做一个整体
- 等价于把这个整体移到
an后面
(a1前面)
- 相对的,操作等价于将
an移到第
x位
- 进一步,所谓
多次operation-1连在一起
其实就是将任意数字移动到任意位置
- 接下来就很简单了
- 我们求出原序列的最长上升子序列
- 对于不在最长上升子序列里的数,我们每一个数花一个
多次operation-1连在一起
移动到正确的位置就好了
Solution 2
- 当你看到
(2≤n≤500)的数据范围
- 容易猜出时复
O(N3)或
O(N2logN)
-
如果你有欧皇血统就像同机房的某大佬
- 就能猜出算法为最长上升子序列
-
如果你能想到这一步,恭喜你得到了朱子百家真传——“看数据,猜算法”
Code(
O(N3))
#include <cstdio>
#include <cstring>
#include <algorithm>
const int N=510;
using namespace std;
int n,ans,a[N],dp[N];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",a+i);
for(int c=1;c<=n;c++){
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++){
dp[i]=1;
for(int j=1;j<i;j++)
if(a[j]<a[i]) dp[i]=max(dp[i],dp[j]+1);
ans=max(ans,dp[i]);
}int tmp=a[1];
for(int i=1;i<n;i++) a[i]=a[i+1];
a[n]=tmp;
}printf("%d\n",n-ans);
}