zoukankan      html  css  js  c++  java
  • 树状数组求逆序对

    逆序对的概念我就不讲了,关于这个求逆序对的问题,通俗的方法自然是要么遍历O(n^2),要么归并排序(nlog n ),那么如何用树状数组实现呢?

    下面看一道题目

    涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度。 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为: ∑(ai-bi)^2

    其中 ai 表示第一列火柴中第 i 个火柴的高度,bi 表示第二列火柴中第 i 个火柴的高度。

    每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小。请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最小交换次数对 99,999,997 取模的结果。

    我将基于这题讲下去

    首先通过数学证明加上离散化我们可以得到一个数组c[i],含义就是对于a火柴盒中的每一个位置i,在b中本该对应的位置(反过来也可以),那么问题就转化成了在c[i]数组中求逆序对的问题

    下面我提供关键代码

    void add(int x,int y){//添加
    
    for(;x<=n;x+=x&-x)
    
        d[x]+=y;
    }
    
    int ask(int x){//询问前缀和
    
    int y=0;
    
    for(;x;x-=x&-x)
    
        y+=d[x];
    
    return y;
    }
    
    for(int i=n;i>=1;i--){
    
    add(c[i],1);
    
    ans+=ask(c[i]-1);
    }

    最后输出ans就好了

    问什么呢???

    仔细分析一下

    假设在ans+=ask(c[i]-1)之中,现在i=i0,有前缀可以给你加,那么这个前缀是怎么来的呢?

    很显然,是通过第一步中来的.那么我们发现,由于i是从n递减,在c[i]中,一定有之前前缀和值个数位于现在的位置之前,并且它们在顺序的数组中的位置还要在c[i0]之前,也就是小于i0。因此我们只需要求前缀和就能知道逆序对的个数。

    由此原理计算逆序对

    星星之火,终将成燎原之势
  • 相关阅读:
    Java面试集合(一)
    Java面试集合(一)
    Android-如何显示版本号并制作3秒跳转页
    Android-如何显示版本号并制作3秒跳转页
    安卓入门教程(十五)- Fragment,Service,WAMP下载
    安卓入门教程(十五)- Fragment,Service,WAMP下载
    网络开发Socket和ServerSocket
    网络开发Socket和ServerSocket
    深入浅出的Java网络通信
    深入浅出的Java网络通信
  • 原文地址:https://www.cnblogs.com/xxzh/p/9154068.html
Copyright © 2011-2022 走看看