https://www.luogu.com.cn/problem/P5149
题目背景:
话说校长最近很喜欢召开全校教职工大会,让老师们强行听他装逼
题目描述:
现在校长在校园网上公布了一份座位表,
n
n
n位老师从左到右依次排成一行。老师们都对这个座位很满意。然而到了开会时,校长不小心把座位表打乱了,老师们很不满。老师们并不在意自己的位置变了多少,但如果有一对老师
a
a
a和
b
b
b,他们原来的座位是
a
a
a在
b
b
b左边,现在变成了
a
a
a在
b
b
b右边,那么这一对老师便会贡献一单位不满值。校长想知道这些老师的总不满值是多少。
输入格式:
第一行一个正整数
n
n
n,为
n
n
n位老师。
第二行有
n
n
n个字符串,每个字符串代表老师的名字(大小写敏感)。这一行代表原来的座位表。
第三行有
n
n
n个字符串,代表打乱后的座位表。
输出格式:
一行,一个正整数,表示老师们的总不满值。
数据范围:
对于
30
%
30\%
30%的数据,
1
≤
n
≤
1
0
3
1\le n \le 10^3
1≤n≤103。
对于
100
%
100\%
100%的数据,
1
≤
n
≤
1
0
5
1\le n \le 10^5
1≤n≤105,每位老师名字长度不超过
5
5
5,只有大小写字母并且互不相同。注意名字对大小写敏感。
其实就是求逆序对个数,可以用归并排序。代码如下:
#include <iostream>
#include <unordered_map>
using namespace std;
const int N = 1e5 + 10;
int n, a[N], tmp[N];
unordered_map<string, int> mp;
long merge_sort(int l, int r) {
if (l == r) return 0;
int mid = l + (r - l >> 1);
long res = merge_sort(l, mid) + merge_sort(mid + 1, r);
int i = l, j = mid + 1, idx = l;
while (i <= mid && j <= r)
if (a[i] <= a[j]) {
res += j - mid - 1;
tmp[idx++] = a[i++];
} else tmp[idx++] = a[j++];
while (i <= mid) tmp[idx++] = a[i++], res += r - mid;
while (j <= r) tmp[idx++] = a[j++];
for (i = l; i <= r; i++) a[i] = tmp[i];
return res;
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
string s;
cin >> s;
mp[s] = i;
}
for (int i = 1; i <= n; i++) {
string s;
cin >> s;
a[i] = mp[s];
}
printf("%ld\n", merge_sort(1, n));
}
时间复杂度 O ( n log n ) O(n\log n) O(nlogn),空间 O ( n ) O(n) O(n)。