题目描述
给定两个长度为n的数组a,b,都是1~n的排列,对于每一个数有两种操作,把这个数移到第一个或者最后一个,其他的数会相对地向前或者向后平移位置。
求把a移成b的最小操作次数。
输入格式
第一行一个n
第二行n个数表示a数组
第三行n个数表示b数组
输出格式
一个数表示最小的操作次数
样例
样例输入
5
4 5 2 3 1
2 3 1 5 4
样例输出
2
数据范围
n≤105
为了方便操作,我们把a,b中的数字替换成改数字在b数组中的下标
那么b[] : 1 2 3 4 5
a[] : 5 4 1 2 3
我们考虑最坏的情况,操作最大为n,顺序从后往前或者从前往后插入,一定能排成b的情况。
那么我们思考在最坏情况下的时候怎么尽量减少操作步数
显然如果一个被处理过的数组,就是上面变换过b[]:1 2 3 4 5的数组和a[]
如果在a[]中能有连续的一段数,那么他们在最终结果的时候也是这样连续的,也就这一段数字可以看做一个数字,不用再操作,那么显然当有多段连续却不符合要求的时候,我们只能忍痛割爱,只维护一个最大的。
因此答案就是n-最大连续子段。
考试的时候本来想到了这个思路,结果在想到多个字段的时候认为不可做,思来思去用处理完的数组打了一个暴力枚举。
C
o
d
e
Code
Code
#include<bits/stdc++.h>
#define N 1001
#define MAXN 200010
#define INF 0x3f3f3f3f
#define gtc() getchar()
#define ll long long
#define rg register
using namespace std;
template <class T>
inline void read(T &s){
T w = 1, ch = gtc(); s = 0;
while(!isdigit(ch)){if(ch == '-') w = -1; ch = gtc();}
while(isdigit(ch)){s = s * 10 + ch - '0'; ch = gtc();}
s *= w;
}
inline void write(ll x){
if(x < 0){
putchar('-'); x = -x;
}
if(x > 9){
write(x/10);
}
putchar(x % 10 + '0');
}
int a[MAXN], b[MAXN], c[MAXN];
int ans = 0;
int n;
int f[MAXN];
map<int, int> mp;
int main()
{
// freopen("sequence.in", "r", stdin);
// freopen("sequence.out", "w", stdout);
read(n); int x;
for(int i = 1; i <= n; ++i) read(a[i]);
for(int i = 1; i <= n; ++i) read(b[i]), mp[b[i]] = i;
for(int i = 1; i <= n; ++i){
c[i] = mp[a[i]];
}
for(int i = 1; i <= n; ++i){
f[c[i]] = f[c[i] - 1] + 1;
ans = max(ans, f[c[i]]);
}
cout << n - ans << endl;
return 0;
}