题目大意:
给定两个数组 a a a 和 b b b , a a a 数组是 1~2n 当中的所有 奇数 的一个排列, b b b 数组是1~2n当中 偶数 的一个排列,现在你可以做如下操作:
- 选择两个序列中的任意一个
- 选择一个位置 i ( 1 ≤ i ≤ n − 1 ) i(1≤i≤n-1) i(1≤i≤n−1),交换 i i i 和 i + 1 i+1 i+1 位置上的数字
计算将 a a a 序列的第一个数小于 b b b 序列的第一个数的最少操作次数。 1 ≤ n ≤ 1 e 5 1≤n≤1e5 1≤n≤1e5
解题思路:
有三种情况:
- 第一种情况,只需要交换 a a a 序列就好了,将第一个小于 b b b 开头元素的交换头部就可以了。
- 第二种情况,只需要交换 b b b 序列就好了,将第一个大于 a a a 开头元素的元素交换到头部就好了。
- 第三种情况, a b a\quad b ab 序列都要移动。
首先,在
b
b
b 数组中记录大于等于bi的最近的位置。
这样,我们就可以遍历
a
a
a 数组,找到对于每个
a
i
ai
ai 来说,相对于b第一个大于
a
i
ai
ai 的元素的位置,然后两个加在一起就是我们需要交换的次数,我们只要遍历的时候不断地取最小值就好了。
关键点在于mp数组的求解:
举个栗子模拟一下:
b数组 | 2 | 8 | 6 | 4 | 10 |
---|---|---|---|---|---|
mp数组初始化 | 1 | 2 | 3 | 4 | 5 |
mp数组更新 | 1 | 2 | 2 | 2 | 5 |
在手动模拟的过程中发现,从大往小更新,那么可以更新到大于等于 b i b_i bi 的所有数字中位置最靠前的那个位置。
代码:
#include <bits/stdc++.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#define ll long long
#define qc ios::sync_with_stdio(false); cin.tie(0);cout.tie(0)
using namespace std;
const int MAXN = 2e5 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
int a[MAXN],b[MAXN],mp[MAXN];
int main()
{
// freopen("in.txt", "r", stdin);
qc;
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++)
{
cin>>b[i];
mp[b[i]]=i;
}
for(int i=2*n-2;i>=2;i-=2)
mp[i]=min(mp[i],mp[i+2]);
int ans=inf;
for(int i=1;i<=n;i++)
ans=min(ans,mp[a[i]+1]+i-1);
cout<<ans-1<<endl;
}
return 0;
}