0818 T2 gloves

原题链接

题目分析

直接暴力的话能以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;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值