其他分享
首页 > 其他分享> > 51nod3121 小陶与杠铃片

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;
}

 

 

标签:杠铃,树状,int,51nod3121,数组,小陶,define
来源: https://blog.csdn.net/ZCH1901/article/details/121109420