最初接觸到逆序數是在離散數學中,逆序數的概念如下:
給出乙個有n個數的序列,如果一對數中前面的數大於後面的數,那麼它們就稱為乙個逆序。乙個序列中逆序的總數就稱為這個排列的逆序數。逆序數的解法有多種,這裡介紹歸併排序、樹狀陣列,時間複雜度均為o(n log n)、如序列 2 4 3 1 的逆序數為4(2和1,4和3,4和1,3和1)
***注:短期內歸併排序的方法更易掌握,文末提供了兩道題目可以練練手~
演算法思想
如對於 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 函式接收乙個...