PAT-TL 1009. Triple Inversions

1、知识点:逆序数
2、思路:求中间节点arr[i]前面比它大的数left_big_num[i],后面比它小的数right_small_num[i],答案就是对left_big_num[i]*right_small_num[i]求和, i从2到n-1。用树状数组计算left_big_num[i],right_small_num[i]可以用一个小技巧间接求得,没必要重复计算。看了网上几篇博文,发现有人用排序离散化,其实由于本题n<10^5,可以不用。

/*用途:
**说明:
**算法:
*/

#define LOCAL
#include <cstdio>
#include <string.h>
using namespace std;
#define MAXN 100000+10
typedef long long LL;

int N;
int arr[MAXN];
int tree_arr[MAXN]; 
LL left_big_num[MAXN];
LL right_small_num[MAXN];

int low_bit(int a);
int get_sum(int ind);
void insert(int ind, int val);
int main()
{
#ifdef LOCAL
    freopen("1009_Triple_Inversions.in", "r", stdin);
    freopen("1009_Triple_Inversions.out", "w", stdout);
#endif
    scanf("%d", &N);
    for(int i=1; i<=N; i++)
        scanf("%d", &(arr[i]));

    if(N < 3){
        printf("0");
        return 0;
    }

    for(int i=1; i<=N; i++){
        int ls = get_sum(arr[i]);//出现在arr[i]前面且比arr[i]小的数的个数
        left_big_num[i] = i-1 - ls;//arr[i]前面出现的所有数的个数减去ls(因为在树状数组中,比arr[i]大的数都插到的arr[i]后面了)
        right_small_num[i] = arr[i]-1-ls;//总共比arr[i]小的数减去左边比它小的数 
        insert(arr[i], 1);//以arr[i]的值为下标插入  
    }

    LL ans = 0;
    for(int i=2; i<=N-1; i++)
        ans += left_big_num[i] * right_small_num[i];

    printf("%lld", ans);

    return 0;
}

inline int low_bit(int a)
{
    return a&(-a);
}

inline int get_sum(int ind)
{
    int sum=0;
    while(ind){
        sum += tree_arr[ind];
        ind -= low_bit(ind);
    }
    return sum;
}

inline void insert(int ind, int val)
{   
    while(ind <= N){
        tree_arr[ind] += val;
        ind += low_bit(ind);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值