AcWing 505. 火柴排队(y总代码理解)
原题链接
困难
作者:
单手剑士三字经
,
2024-12-24 22:25:01
,
所有人可见
,
阅读 4
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
// 记一下逆序对,将一个数组通过相邻元素交换的方式达到有序(升序),
// 所需要的交换次数至少是逆序对的个数,并且可以到达这个次数
//1)交换次数就是如果把其中一个序列当做有序,另一个序列达到
//这个有序状态需要进行的操作
//2)具体操作并不是如1所说,而是通过下面的work方法找到p:即将将一个序列变为有序,
// 所需要进行的操作
//3)这里对两个序列同时进行这个p操作,使第一个序列达到有序,第二个序列便可用来求逆序对
/*
关于对work()的理解,中间状态p:p[i]即第i个位置应当放第p[i]个数
操作结果a: a[i]即第i个数应该放到第a[i]个位置
两者可以通过 for (int i = 1; i <= n; i ++ ) a[p[i]] = i;
和 for (int i = 1; i <= n; i ++ ) p[a[i]] = i;
相互转化
但是只用这种方式理解会很难,可以用另一种方式理解,
中间状态p:即一种变换
操作结果a: 原操作目标的相对大小转换,即结果a的逆序对个数和将会输入a相同,相对大小其实是不变的
*/
const int N = 100010, MOD = 99999997;
int n;
int a[N], b[N], c[N], p[N];
void work(int a[])
{
for (int i = 1; i <= n; i ++ ) p[i] = i;
sort(p + 1, p + n + 1, [&](int x, int y) {
return a[x] < a[y];
});
for (int i = 1; i <= n; i ++ ) a[p[i]] = i;
}
int merge_sort(int l, int r)
{
if (l >= r) return 0;
int mid = l + r >> 1;
int res = (merge_sort(l, mid) + merge_sort(mid + 1, r)) % MOD;
int i = l, j = mid + 1, k = 0;
while (i <= mid && j <= r)
if (b[i] < b[j]) p[k ++ ] = b[i ++ ];
else p[k ++ ] = b[j ++ ], res = (res + mid - i + 1) % MOD;
while (i <= mid) p[k ++ ] = b[i ++ ];
while (j <= r) p[k ++ ] = b[j ++ ];
for (i = l, j = 0; j < k; i ++, j ++ ) b[i] = p[j];
return res;
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);
for (int i = 1; i <= n; i ++ ) scanf("%d", &b[i]);
work(a), work(b);
for (int i = 1; i <= n; i ++ ) c[a[i]] = i;
for (int i = 1; i <= n; i ++ ) b[i] = c[b[i]];
printf("%d\n", merge_sort(1, n));
return 0;
}