51nod3121 小陶与杠铃片

3121 小陶与杠铃片

小陶在举重队负责后勤工作。举重队的训练场中有一个区域一排码放了n片杠铃片,每天运动员们训练完之后会将杠铃片放回,之后小陶需要重新整理杠铃片的顺序,使它们由轻到重依次排好。由于杠铃片很重,小陶每次只能选两片相邻的杠铃片,交换它们的位置。现在小陶想知道,这一天他至少需要交换多少次才能整理完毕?

已知n<=200000,0<=杠铃片重量<=200000。

输入

第一行一个正整数n,表示有n片杠铃片;
第二行n个整数,表示运动员们放回后每片杠铃片依次的重量。

输出

输出一个整数,表示小陶至少交换的次数。

数据范围

对于30%的数据: n<=5000
对于60%的数据: n<=30000
对于100%的数据: n<=200000,0<=杠铃片重量<=200000

输入样例

10
16808 75250 50074 143659 108931 11273 27545 50879 177924 37710

输出样例

20

解析:

树状数组求逆序对

对于序列中的每个数a_{j},如果我们能设法快速找出有多少个a_{j},满足i<j且a_{i}>a_{j}就好了 

其实也可以先找满足i<j且a_{i}< = a_{j}的个数cnt,那么j-cnt就是我们上面要求的数量

怎么找呢?

我们可以用树状数组去维护这样一个数组: num[i]表示权值为i的数的个数。

那么我们依次枚举每个数并将其加入树状数组,在需要统计满足i<j且a_{i}< = a_{j}的个数时,我们使得树状数组里加入了a_{1},a_{2},...a_{j-1},然后在树状数组中统计num_{1}+num_{2}+...+num_{aj}即可,这是一段区间和,而且是一段前缀和,非常容易求出。

放代码:

#include<bits/stdc++.h>
using namespace std; 
#define lowbit(i) (i & -i)
#define MX 200000
#define N 200020
int n;
int a[N], C[N];
void add(int x, int c) {
    for (int i = x; i <= MX; i += lowbit(i))
        C[i] += c;
}
int ask(int x) {
    int ret = 0;
    for (int i = x; i; i -= lowbit(i))
        ret += C[i];
    return ret;
}
long long ans;
int main() {
    ios::sync_with_stdio(false);
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    for (int i = 1; i <= n; i++) {
        ans += (i - 1) - ask(a[i]);
        add(a[i], 1);
    }
    cout << ans << endl;
}

 

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值