这是一道逆序对变形题
可以这样理解题意:给你一个数组a一个数组b 然后b是一个偏序集合来定义这题的大小比较
比如现在给你a数组为 1 3 2 4 b数组为3 1 2 4
那如果以b为偏序集合的话这题里就有3<1<2<4 然后由1<2<3<4可知
其实3的真实值应该是1才对 1的真实值应该是2才对 2的真实值应该是3才对 4的真实值应该是4才对
那我们就可以知道a数组的真实值应该是 2 1 3 4 然后在真实值的情况下只要a按1<2<3<4排好就等同于a的原值 1 3 2 4 按3<1<2<4排好了
然后问题就转化成了如何将2 1 3 4排成1 2 3 4然后花费最少步数 由于题目是问要最少多少步可以达到目的 那就说明肯定是有答案的 也就是可排的 那我们每次就只需要找不符合排序方式的相邻的逆序对就行调转就好 这样就能将逆序对减一 直到没有逆序对了(也就是按要求排好了)
所以最终问题就转化成了将a的值改成真实值 最终求它的逆序对总数就是最少的移动步数了
关于逆序对的求法如果有不会的建议先做洛谷p1908再来做这题
实现于下:
#include <iostream>
#include <algorithm>
using namespace std;
const int mod=99999997;
struct node
{
int value, num;//value是题目给的值 num是它的编号
bool friend operator<(node a, node b)
{
return a.value < b.value;
}
};
node a[100005];
node b[100005];
int f[100005];
int t[100005];
int fun(int f[], int l, int r)//此函数为纯纯求f数组[l,r]的逆序对模板
{
if (l >= r)
return 0;
int mid = (l + r) >> 1;
int x = fun(f, l, mid)%mod;
int y = fun(f, mid + 1, r)%mod;//记得取模
int tmp = 0;
for (int i = l, j = l, k = mid + 1; i <= r; i++)
{
if (j == mid + 1)
t[i] = f[k++];
else if (k == r + 1)
{
t[i] = f[j++];
tmp += i - j + 1;
tmp%=mod;
}
else
{
if(f[j]<f[k])
{
t[i]=f[j++];
tmp+=i-j+1;
tmp%=mod;
}
else
{
t[i]=f[k++];
}
}
}
for(int i=l;i<=r;i++)
f[i]=t[i];
return (x+y+tmp)%mod;
}
int main()
{
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i].value);
a[i].num = i;
}
for (int i = 1; i <= n; i++)
{
scanf("%d", &b[i].value);
b[i].num = i;
}
sort(a + 1, a + 1 + n);
sort(b + 1, b + 1 + n);
//a[i].num是找出它原本在第几个 然后改成按b的偏序集的偏好(即真实值)即可
for (int i = 1; i <= n; i++)
f[a[i].num] = b[i].num;
//得到a的真实值数组丢去求逆序对数量
cout<<fun(f, 1, n)<<endl;
return 0;
}