题解 P5149 【会议座位】
当你看到我的时候,就知道这是道水题
P5149 题解
题目本质:求逆序对
因此我们可以很容易的把这道题分为两部分:
- 求顺序。
- 求逆序对。
找到了题目切入点就可以开始切了
第一部分,可以使用Hash、Trie、甚至Map。而我推荐Trie,因为好打、较快、无错。为了获得顺序,我们只需要将附加数组记录顺序即可,代码如下:
void insert(char s[], int k) {
int u = 1;
int len = strlen(s);
for (int i = 0; i < len; i++) {
int a = s[i] - 'a';
if (!ch[u][a]) ch[u][a] = ++tot;
u = ch[u][a];
}
cnt[u] = k;
return;
}
void find(char s[], int k) {
int u = 1;
int len = strlen(s);
for (int i = 0; i < len; i++) {
int a = s[i] - 'a';
u = ch[u][a];
}
finded[k] = cnt[u];
}
完成这一部分,我们很容易就得到了坐位顺序,那么我们只需要求逆序对即可:
void MergeSort(int l, int r) {
if (l == r) return;
int mid = (l + r) >> 1;
MergeSort(l, mid), MergeSort(mid + 1, r);
int i = l, j = mid + 1, t = l;
while (i <= mid && j <= r)
if (finded[i] <= finded[j])
b[t++] = finded[i++];
else
b[t++] = finded[j++], ans += mid - i + 1;
while (i <= mid) b[t++] = finded[i++];
while (j <= r) b[t++] = finded[j++];
for (int k = l; k <= r; ++k) finded[k] = b[k];
}
什么这不是归并排序嘛?
没错!但我加了一句话,看看
else
b[t++] = finded[j++], ans += mid - i + 1;
就是在这里,我们统计了每次排序不符合顺序的个数,因此就得到了逆序对个数。
现在我们已经完成了两个部分,结合即可了,上完整代码:
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int MAXN = 5e5 + 5;
int ch[MAXN][26 * 2], cnt[MAXN];
int n, ans, tot = 1, finded[int(1e5 + 5)], b[int(1e5 + 5)];
char s[6];
void insert(char[], int);
void find(char[], int);
void MergeSort(int, int);
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%s", s);
insert(s, i);
}
for (int i = 1; i <= n; i++) {
scanf("%s", s);
find(s, i);
}
MergeSort(1, n);
cout << ans;
}
void insert(char s[], int k) {
int u = 1;
int len = strlen(s);
for (int i = 0; i < len; i++) {
int a = s[i] - 'a';
if (!ch[u][a]) ch[u][a] = ++tot;
u = ch[u][a];
}
cnt[u] = k;
return;
}
void find(char s[], int k) {
int u = 1;
int len = strlen(s);
for (int i = 0; i < len; i++) {
int a = s[i] - 'a';
u = ch[u][a];
}
finded[k] = cnt[u];
}
void MergeSort(int l, int r) {
if (l == r) return;
int mid = (l + r) >> 1;
MergeSort(l, mid), MergeSort(mid + 1, r);
int i = l, j = mid + 1, t = l;
while (i <= mid && j <= r)
if (finded[i] <= finded[j])
b[t++] = finded[i++];
else
b[t++] = finded[j++], ans += mid - i + 1;
while (i <= mid) b[t++] = finded[i++];
while (j <= r) b[t++] = finded[j++];
for (int k = l; k <= r; ++k) finded[k] = b[k];
}
后记:
于是,你拿去交了;于是,你发现WA了4个点:
你忘了,不开