题目分析
直接暴力的话能以O(n^2)的姿态通过六组。
对于暴力没写出来的同学深表遗憾。
其实正解很简单。
一句话总结:重新编号求逆序对。
好了,讲完了(不要打我//溜)
具体解释
可以贪心地考虑一下,每次找到一双手套的前半只,在将后半只移动到它的后边就好了,这样做是不会影响原序列其他数的。(想一想为什么)
这样的话我们可以O(n)求出应得的序列是什么。
就是每次找到前半只手套,然后为其重新编号就可以了。
在这里呢,我们采用树状数组求逆序对的方法,O(nlogn)。
就是在每次插入的时候统计有多少比他大的就可以了。
代码
#include<cstdio>
const int maxn = 400044;
int n, p[maxn];
long long ans, tot, a[maxn], tr[maxn], w;
int main() {
scanf("%d", &n);
n <<= 1;
for(int i = 1; i <= n; ++i) {
scanf("%d", a+i);
++a[i];
if(!p[a[i]]) p[a[i]] = i;//重新编号
w = 0;
for(int j = p[a[i]]; j >= 1; j -= (j&-j))
w += tr[j];
ans += tot - w;
++tot;
for(int j = p[a[i]]; j <= n; j += (j&-j))
++tr[j];
}
printf("%lld\n", ans);
return 0;
}