【题意】:给出n个数组成的一个序列,我们可以把前m个数移到序列的后面,这样我们一共可以得到n个不同的序列。求这n个序列中,逆序对最小为多少。

【题解】:可以利用树状数组或者线段树在O(nlogn)时间里求出初始序列的逆序对,然后每次用O(1)的时间推出每移动一个数到序列后面之后的逆序对。
               总复杂度O(nlogn + n)。

【代码】:
 1 #include "iostream"
 2 #include "cstdio"
 3 #include "cstring"
 4 #include "algorithm"
 5 #include "vector"
 6 #include "queue"
 7 #include "cmath"
 8 #include "string"
 9 using namespace std;
10 #define pb push_back
11 #define lc(x) (x << 1)
12 #define rc(x) (x << 1 | 1)
13 #define lowbit(x) (x & (-x))
14 #define ll long long
15 #define maxn 5005
16 const int inf = 1 << 30;
17 int sum[maxn], n, val[maxn];
18 
19 void update(int x) {
20     for(int i = x; i < maxn; i += lowbit(i))
21         sum[i]++;
22 }
23 
24 int SUM(int x) {
25     int res = 0;
26     for(int i = x; i; i -= lowbit(i))
27         res += sum[i];
28     return res;
29 }
30 
31 int main() {
32     while(~scanf("%d", &n)) {
33         memset(sum, 0, sizeof(sum)); 
34         int ans = inf, tmp = 0;
35         for(int i = 0; i < n; i++) {
36             scanf("%d", &val[i]);
37             tmp += SUM(n) - SUM(val[i]);
38             update(val[i]+1);
39         }
40         for(int i = 0; i < n - 1; i++) {
41             tmp += n - 2 * val[i] - 1;
42             ans = min(ans, tmp);
43         }
44         cout << ans << endl;
45     }
46     return 0;
47 }
48