[机房练习赛] 题解 求逆序对

大家都很强, 可与之共勉。

如果你有一个长度为n 的序列:
a1; a2; a3; : : : ; an
那么它的一个逆序对是一个二元组:< i; j > 满足i < j 且ai > aj,其中i; j 2 [1; n]。
我们称一个序列所包含的逆序对的个数为这个序列的逆序对数。
那么问题来了:
我给出一个长度为n 的序列,需要你计算:
a1; a2 : : : an-1; an
a2; a3 : : : an; a1
a3; a4 : : : a1; a2

an; a1 : : : an-2; an-1
这n 个序列的逆序对之和。
Input
输入文件包含2 行:
第1 行1 个整数:n,表示给定序列的长度。
第2 行n 个整数:a1 a2 : : : an,表示初始序列。
Output
输出n 个序列的逆序对的和。
Sample
rotinv.in
3
2 2 3
rotinv.out
6
以上样例中,3 个序列分别是:2 2 3,2 3 2,3 2 2,分别有0,1,2 个逆序对,所以和为6。
rotinv.in
3
1 1 1
rotinv.out
0
以上样例中,3 个序列都是:1 1 1,逆序对数为0,所以答案为0。
Note
• 对于30% 的数据,1 n 300
• 对于60% 的数据,1 n 5000
• 对于100% 的数据,1 n 106,1 ai n

#include "cctype"
#include "cstdio"
#include "cstring"
#include "algorithm"

#define lowbit(x)  ((x) & (-x))
#define abs(a)  ((a) < 0 ? (-(a)) : (a))
#define max(a, b)  ((a) > (b) ? (a) : (b))
#define min(a, b)  ((a) < (b) ? (a) : (b))

#define rep(_, m, n)  for(register int _ = (m); i <= (n); ++i)
#define res(_, n, m)  for(register int _ = (n); i >= (m); --i)
#define edges(u)  for(register int _ = head[u]; _; _ = g[i].pre)

template <class T>
inline bool readIn( T &x )  {
    char ch;
    T opt = 1;
    while( !isdigit(ch = (char) getchar()) && (ch ^ -1) )  if( ch == '-' )  opt = -1;
    if( !(ch ^ -1) )  return false;
    for( x = ch - 48; isdigit(ch = (char) getchar()); x = (x << 1) + (x << 3) + ch - 48 );
    x *= opt;
    return true;
}

template <class T>
inline void write( T x )  {
    if( x > 9 )
        write(x / 10);
    putchar( x % 10 + 48 );
}

template <class T>
inline bool writeIn( T x )  {
    if(x < 0)  {
        x = -x;
        putchar('-');
    }
    write(x);
    return  true;
}

class io  {
public:
    #define SIM "rotinv"
    io()  {
        freopen(SIM ".in", "r", stdin);
        freopen(SIM ".out", "w", stdout);
    }
    ~io()  {
        fclose(stdin);
        fclose(stdout);
    }
} WhiteBunny;

typedef long long LL;

const int MAXN = (int) 1e6 + 5;

int n, bit[MAXN], a[MAXN];
LL ans, cnt;

inline bool modify(int pos, int delta)  {
    for(register int i = pos; i <= n; i += lowbit(i))
        bit[i] += delta;
}

inline LL query(int r)  {
    int rt = 0;
    for(register int i = r; i; i -= lowbit(i))
        rt += bit[i];
    return rt;  
}

int main()  {
    readIn(n);
    rep(i, 1, n)  readIn(a[i]);
    rep(i, 1, n)  {
        cnt += (i - 1) - query(a[i]); 
        modify(a[i], 1);  
    }
    rep(i, 1, n)  {
        modify(a[i], -1);
        cnt += (n - 1) - query(a[i]);
        cnt -= query(a[i] - 1);
        modify(a[i], 1);
        ans += cnt;
    }
    writeIn(ans);
    putchar(10);
    return 0;
}

代码骚起来

#include "cctype"
#include "cstdio"
#include "cstring"
#include "algorithm"

#define lowbit(x)  ((x) & (-x))
#define abs(a)  ((a) < 0 ? (-(a)) : (a))
#define max(a, b)  ((a) > (b) ? (a) : (b))
#define min(a, b)  ((a) < (b) ? (a) : (b))

#define rep(_, m, n)  for(register int _ = (m); i <= (n); ++i)
#define res(_, n, m)  for(register int _ = (n); i >= (m); --i)
#define edges(u)  for(register int _ = head[u]; _; _ = g[i].pre)

template <class T>
inline bool readIn( T &x )  {
    char ch;
    T opt = 1;
    while( !isdigit(ch = (char) getchar()) && (ch ^ -1) )  if( ch == '-' )  opt = -1;
    if( !(ch ^ -1) )  return false;
    for( x = ch - 48; isdigit(ch = (char) getchar()); x = (x << 1) + (x << 3) + ch - 48 );
    x *= opt;
    return true;
}

template <class T>
inline void write( T x )  {
    if( x > 9 )
        write(x / 10);
    putchar( x % 10 + 48 );
}

template <class T>
inline bool writeIn( T x )  {
    if(x < 0)  {
        x = -x;
        putchar('-');
    }
    write(x);
    return  true;
}

class io  {
public:
    #define SIM "rotinv"
    io()  {
        freopen(SIM ".in", "r", stdin);
        freopen(SIM ".out", "w", stdout);
    }
    ~io()  {
        fclose(stdin);
        fclose(stdout);
    }
} WhiteBunny;

typedef long long LL;

const int MAXN = (int) 1e6 + 1;

int n, bit[MAXN], a[MAXN];
LL ans, cnt;

inline bool modify(int pos, int delta)  {
    for(register int i = pos; i <= n; i += lowbit(i))
        bit[i] += delta;
}

inline int query(int r)  {
    int rt = 0;
    for(register int i = r; i; i -= lowbit(i))
        rt += bit[i];
    return rt;  
}

int main()  {
    readIn(n);
    rep(i, 1, n)  readIn(a[i]), cnt += (i - 1) - query(a[i]), modify(a[i], 1);  
    rep(i, 1, n)
        modify(a[i], -1),  (cnt += (n - 1) - query(a[i])) -= query(a[i] - 1),
        modify(a[i], 1),  ans += cnt;
    writeIn(ans);
    putchar(10);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值