hdu1394 minimum inversion number
題意:求inversion後的最小逆序數
思路:用o(nlogn)複雜度求出最初逆序數後,就可以用o(1)的複雜度分別遞推出其他解
線段樹功能:update:單點增減 query:區間求和
逆序數: 對於
n個不同
的元素,先規定各元素之間有乙個標準次序(例如n個 不同的自然數,可規定從小到大為標準次序),於是在這n個元素的任一排列中,當某兩個元素的先後次序與標準次序不同時,就說有1個逆序。乙個排列中所有逆序總數叫做這個排列的逆序數
在乙個排列中,如果一對數的前後位置與大小順序相反,即前面的數大於後面的數,那麼它們就稱為乙個
逆序。乙個排列中逆序的總數就稱為這個排列的
逆序數。逆序數為
偶數的排列稱為
偶排列;逆序數為奇數的排列稱為
奇排列。如2431中,21,43,41,31是逆序,逆序數是4,為偶排列。
首先,求逆序數對的思路:
1.得到整個數列後,從前往後掃,統計比a[i]小的,在a[i]後面的有多少個
這樣做的話,應該是只有n2的暴力作法
2.統計a[i]前面的且比它大的數
這樣做的話,就可以利用輸入的時效性,
統計比這個數大的數的num和,
然後把把這個和加到總逆序數sum裡。
這樣做的話直接的暴力作法依然是n2,但是,
我們可以在,
統計比這個數大的數的num和這一步進行優化,利用線段樹求區間域值的複雜度是logn,
所以總體複雜度就降到了nlogn。
再來看這道題,求得初始數列的逆序數後,再求其他排列的逆序數有乙個規律,就是
sum = sum + (n - 1 - a[i]) - a[i];
這個自行驗證吧,相信很容易得出
最後,拓展一下,如果要求正序數怎麼辦?很簡單,無非是大小調一下
再問,如果要求滿足ia[j]>a[k]的數對總數怎麼辦?
可以從中間的這個數入手,統計a[i]>a[j]的對數m,以及a[j]>a[k]的對數n,m*n就是。。。
要求a[i]>a[j]的個數還是一樣的,那麼a[j]>a[k]的個數呢?
兩種思路:
1.得到a[i]>a[j]的對數後,將數列倒過來後再求a[j]2.更簡單的做法是,找到規律發現,n = 整個數列中比a[j]小的數 — 在a[j]前面已經出現的比a[j]小的數的個數
即(假設數列是從1開始的) n = (a[j] -1) - (j - 1 - m )
本題處理:
#include #define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int maxn = 5555;
int a[maxn];
struct treetree[maxn<<2];
void pushup(int rt)
void build(int l,int r,int rt)
int m = (l + r) >> 1;
build(lson);
build(rson);
//pushup(rt); 這題初始化0 沒必要這步了
} void update(int p,int l,int r,int rt)
int m = (l + r) >> 1;
if (p <= m) update(p , lson);
else update(p , rson);
pushup(rt); //這步需要,
} int query(int l,int r,int l,int r,int rt)
int m = (l + r) >> 1;
int ret = 0;
if (l <= m) ret += query(l , r , lson); //找到最底部
if (r > m) ret += query(l , r , rson);
return ret;
} int main()
ans = sum;//先讓ans為初始順序的值
for(i = 1;i < n;i++){
sum = sum + (n - 1 - a[i]) - a[i];//重點步驟注意理解
ans = ans
逆序數 線段樹
既然是區間操作 我們想到了線段樹 我們先建立乙個空樹 然後呢 按照這個序列的順序將每個值插入 每次插入伴隨一次查詢 查詢前面插入的比這次插入的大的數字的個數 然後就可以了 複雜度 nlogn 可以接受 題意 就是給出一串數,當依次在將第乙個數變為最後乙個數的過程中,要你求它的最小逆序數。思路 可以用...
hdu 1394 求逆序數(線段樹求)
題意描述 給你乙個有0 n 1數字組成的序列,然後進行這樣的操作,每次將最前面乙個元素放到最後面去會得到乙個序列,那麼這樣就形成了n個序列,那麼每個序列都有乙個逆序數,找出其中最小的乙個輸出!解析 求出a1,a2,an 1,an的逆序數之後,就可以遞推求出其他序列的逆序數。假設要把a1移動到an之後...
線段樹或樹狀陣列求逆序數
線段樹或樹狀陣列求逆序數 求逆序數的方法有分治,歸併,本文只介紹線段樹或樹狀陣列求逆序數的辦法,眾所周知,線段樹和樹狀樹可以用來解決區間操作問題,就是因為這兩個演算法區間操作的時間複雜度很低o logn 才讓這種方法具有可行性。首先先來看乙個序列 6 1 2 7 3 4 8 5,此序列的逆序數為5 ...