1、什麼是逆序數? 2、用樹狀數組求逆序數的總數 2.1該背景下樹狀數組的含義 2.2如何使用樹狀數組求逆序數總數 2.3 C++實現代碼
一、什麼是逆序數?ios
在一個排列中,若是一對數的先後位置與大小順序相反,即前面的數大於後面的數,那麼它們就稱爲一個逆序。一個排列中逆序數的總數就是這個排列的逆序數。數組
二、用樹狀數組求逆序數的總數ide
2.1該背景下樹狀數組的含義函數
咱們假設一個數組A[n],當A[n]=0時表示數字n在序列中沒有出現過,A[n]=1表示數字n在序列中出現過。A對應的樹狀數組爲c[n],則c[n]對應維護的是數組A[n]的內容,即樹狀數組c可用於求A中某個區間的值的和。spa
樹狀數組的插入函數(假設爲 void insert(int i,int x) )的含義:在求逆序數這個問題中,咱們的插入函數一般使用爲insert( i , 1 ),即將數組A[i]的值加1 (A數組開始應該初始化爲0,因此也能夠理解爲設置A[ i ]的值爲1,即將數字i 加入到序列的意思 )。,同時維護c數組的值。code
樹狀數組中區間求和函數(假設函數定義爲: int getsun(int i ) )的含義:該函數的做用是用於求序列中小於等於數字 i 的元素的個數。這個是顯而易見的,由於樹狀數組c 維護的是數組A的值,則該求和函數便是用於求下標小於等於 i 的數組A的和,而數組A中元素的值要麼是0要麼是1,因此最後求出來的就是小於等於i的元素的個數。blog
因此要求序列中比元素a大的數的個數,能夠用i - getsum(a)便可( i 表示此時序列中元素的個數)。ci
2.2如何使用樹狀數組求逆序數總數get
首先來看如何減少問題的規模:string
要想求一個序列 a b c d,的逆序數的個數,能夠理解爲先求出a b c的逆序數的個數k1,再在這個序列後面增長一個數d,求d以前的那個序列中值小於d的元素的個數k2,則k1+k2即爲序列a b c d的逆序數的個數。
舉個例子加以說明:
假設給定的序列爲 4 3 2 1,咱們從左往右依次將給定的序列輸入,每次輸入一個數temp時,就將當前序列中大於temp的元素的個數計算出來,並累加到ans中,最後ans就是這個序列的逆序數個數。
序列的變化(下劃線爲新增長元素) |
序列中大於新增長的數字的個數 |
操做 |
{ } |
0 |
初始化時序列中一個數都沒有 |
{4 } |
0 |
往序列中增長4,統計此時序列中大於4的元素個數 |
{4 3 } |
1 |
往序列中增長3,統計此時序列中大於3的元素個數 |
{4 3 2} |
2 |
往序列中增長2,統計此時序列中大於2的元素個數 |
{4 3 2 1} |
3 |
往序列中增長1,統計此時序列中大於1的元素個數 |
當全部的元素都插入到序列後,便可獲得序列{4 3 2 1}的逆序數的個數爲1+2+3=6.
2.3 C++實現代碼以下:
#include <iostream> #include <string> using namespace std; #define N 1010 int c[N]; int n; int lowbit(int i) { return i&(-i); } int insert(int i,int x) { while(i<=n){ c[i]+=x; i+=lowbit(i); } return 0; } int getsum(int i) { int sum=0; while(i>0){ sum+=c[i]; i-=lowbit(i); } return sum; } void output() { for(int i=1;i<=n;i++) cout<<c[i]<<" "; cout<<endl; } int main() { while(cin>>n){ int ans=0; memset(c,0,sizeof(c)); for(int i=1;i<=n;i++){ int a; cin>>a; insert(a,1); ans+=i-insert(a);//統計當前序列中大於a的元素的個數 } cout<<ans<<endl; } return 0; }