藍橋杯AcWing 專題 逆序數(重點)

2021-10-21 21:29:41 字數 3325 閱讀 6202

最初接觸到逆序數是在離散數學中,逆序數的概念如下:

給出乙個有n個數的序列,如果一對數中前面的數大於後面的數,那麼它們就稱為乙個逆序。乙個序列中逆序的總數就稱為這個排列的逆序數。

如序列 2 4 3 1 的逆序數為4(2和1,4和3,4和1,3和1)

逆序數的解法有多種,這裡介紹歸併排序、樹狀陣列,時間複雜度均為o(n log n)、

***注:短期內歸併排序的方法更易掌握,文末提供了兩道題目可以練練手~

演算法思想

如對於 2 4 3 1 只標記較大數,逆序記錄為 1 2 1 0

歸併後的結果:

a.val 1 2 3 4

a.num 0 1 1 2

————————————開始歸併————————————

#include using namespace std;

const int maxn = 100005;

struct note;

struct note a[maxn], b[maxn];

void merge(int l, int mid, int r)else

} while(i <= mid)

while(j <= r)

for(k = l; k <= r; ++k)

}void mergesort(int l, int r)

}int main()

mergesort(0, n-1);

int ans = 0;

for(int i = 0; i < n; ++i)

cout << ans 《其實記錄逆序的過程有助於對歸併過程的加深理解;

解釋一下merge()中的這兩行吧:

b[k-1].num += (r-mid);

b[k-1].num += (j-mid-1);

正因為merge()是對兩組有序的序列合併,所以這兩行記錄的是,a[i].val後面比它小的有多少;

演算法思想

構建c[1:n]的樹狀陣列(考慮到a可能資料過大,可以離散化一下,後面會有介紹),初始化為0

從後往前遍歷時,單值更新a[i]+1,區間加1即可,每次單值查詢即可

還原一下逆序遍歷2 4 3 1過程中錄入c的原資料 a的變化吧

c的原資料 a:

a[1] a[2] a[3] a[4]

0 1 0 0

0 1 0 1

0 1 0 1

0 1 1 1

單點更新即可,樹狀陣列實現對其區間求和依次為0 1 2 1,最後累加得到逆序數

————————————完整**————————————

#include #include using namespace std;

const int maxn = 100005;

int n;

int tree[maxn], hash[maxn];

int data[maxn];

struct notea[maxn];

bool comp(struct note x, struct note y)

int lowbit(int x)

void updata(int i, int temp)

}int getsum(int i)

return res;

}int main()//離散化

sort(a+1, a+n+1, comp);

for(int i = 1; i <= n; ++i)

int ans = 0;

for(int i = n; i >= 1; --i)

} cout << ans << endl;

return 0;

}

***注:不就是單點更新,區間求和嗎,線段樹也可以搞定,但還是樹狀陣列實現起來簡單些

————————————完整**————————————

#include using namespace std;

typedef long long ll;

const int maxn = 1e5 + 5;

int n;

struct note;

struct note a[maxn], b[maxn];

void merge(int l, int middle, int r)else

} while(low <= middle)

while(high <= r)

for(int i = l; i <= r; ++i)

}void mergesort(int l, int r)

}int main()

mergesort(0, n-1);

ll ans = 0;

for(int i = 0; i < n; ++i)

printf("%lld\n", ans);

return 0;

}

如輸入樣例:

33 2 1

——————

逆序後的結果為

a.val 1 2 3

a.num 2 2 2

對於1,需要交換兩次,而不高興程度是累加的,因此最後是1+2

————————————完整**————————————

#include using namespace std;

typedef long long ll;

const int maxn = 1e5 + 5;

int n;

struct note;

struct note a[maxn], b[maxn];

void merge(int l, int middle, int r)else

} while(low <= middle)

while(high <= r)

for(int i = l; i <= r; ++i)

}void mergesort(int l, int r)

}int main()

mergesort(0, n-1);

ll ans = 0;

for(int i = 0; i < n; ++i)

printf("%lld\n", ans);

return 0;

}

藍橋杯AcWing 專題 二分(重點)

優雅的二分可以使複雜度達到o n log n 首先保證的是,二分查詢的序列是公升序的。查詢小於等於temp的第乙個元素位置 void binary lower int temp else printf d n l 查詢大於temp的第乙個元素位置 void binary upper int temp...

藍橋杯 逆序排列

問題描述 編寫乙個程式,讀入一組整數 不超過20個 並把它們儲存在乙個整型陣列中。當使用者輸入0時,表示輸入結束。然後程式將把這個陣列中的值按逆序重新存放,並列印出來。例如 假設使用者輸入了一組資料 7 19 5 6 2 0,那麼程式將會把前五個有效資料儲存在乙個陣列中,即7 19 5 6 2,然後...

1101 逆序數字(函式專題)

1101 逆序數字 函式專題 時間限制 1 sec 記憶體限制 128 mb 提交 13913 解決 7206 狀態 討論版 提交 命題人 admin 題目描述 輸入乙個正整數n,計算n的逆序數m,輸出m與n的和。要求程式定義乙個inverse 函式和乙個main 函式,inverse 函式接收乙個...