首先介紹一下逆序數的概念:在乙個排列中,如果一對數的前後位置與大小順序相反,即前面的數大於後面的數,那麼它們就稱為乙個逆序。乙個排列中逆序的總數就稱為這個排列的逆序數。逆序數為偶數的排列稱為偶排列;逆序數為奇數的排列稱為奇排列。如2431中,21,43,41,31是逆序,逆序數是4,為偶排列。
應用線段樹資料結構,將複雜度降到o(
nlog
n),首先求初始狀態下的逆序數。在構造完線段樹後(見下面程式中的build()函式),根據輸入的資料x,累加區間[x,n](也即已經輸入的並且比x大的數的個數)的和,然後更新對應葉節點的值,由0變為1,表示這個數已經輸入,並遞迴更新父節點(等於左右兒子節點值得和)。
在求出初始狀態下的逆序數num後,在每次將第乙個數移動到最後的過程中,逆序數的變化有一下遞推公式: nu
m=nu
m−in
put[
i]+(
n−in
put[
i]−1
) 其中num為初始狀態下的逆序數,input為輸入的陣列,n為輸入資料的總數。
ac的**如下:
#include
#include
#include
using
namespace
std;
#define max 5010
int tree[max<<2];
int input[max];
void build(int l, int r, int rt)
int m = (l+r)/2;
build(l,m,rt<<1);
build(m+1,r,(rt<<1)+1);
tree[rt] = 0;
}void update(int p, int l, int r, int rt)
int m = (l+r)/2;
if(p<=m)
update(p,l,m,rt<<1);
else
update(p,m+1,r,(rt<<1)+1);
tree[rt] = tree[rt<<1] + tree[(rt<<1)+1];
}int getsum(int l, int r, int l, int r, int rt)
int main()
int num = ans;
for(int i=0; i1; i++)
cout
0;}
使用樹狀陣列資料結構會更加方便,ac**如下:
#include
#include
#include
using
namespace
std;
#define max 5010
int tree[max<<2];
int input[max];
int n;
int lowbit(int x)
void update(int i)
}int getsum(int i)
return s;
}int main()
int num = ans;
for(int i=0; i1; i++)
cout
0;}
排列的逆序數
在乙個排列中,如果一對數的前後位置與大小順序相反,即前面的數大於後面的數,那麼它們就稱為乙個逆序。乙個排列中逆序的總數就稱為這個排列的逆序數。也就是說,對於n個不同的元素,先規定各元素之間有乙個標準次序 例如n個 不同的自然數,可規定從小到大為標準次序 於是在這n個元素的任一排列中,當某兩個元素的實...
求排列的逆序數
考慮1,2,n n 100000 的排列i1,i2,in,如果其中存在j,k,滿足 j k 且 ij ik,那麼就稱 ij,ik 是這個排列的乙個逆序。乙個排列含有逆序的個數稱為這個排列的逆序數。例如排列 263451 含有8個逆序 2,1 6,3 6,4 6,5 6,1 3,1 4,1 5,1 因...
求排列的逆序數
openjudge011 題目 乙個排列含有逆序的個數稱為這個排列的逆序數。例如排列 263451 含有8個逆序 2,1 6,3 6,4 6,5 6,1 3,1 4,1 5,1 因此該排列的逆序數就是8。顯然,由1,2,n 構成的所有n 個排列中,最小的逆序數是0,對應的排列就是1,2,n 最大的逆...