明知道是线段树,却写不出来,搞了半天,戳,没办法,最后还是得去看题解(有待于提高啊啊),想做道题还是难啊。
还是先贴题吧
HDU-1394 Minimum Inversion Number
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 8324 Accepted Submission(s): 5115
Problem Description
The
inversion number of a given number sequence a1, a2, ..., an is the
number of pairs (ai, aj) that satisfy i < j and ai > aj.
For a given sequence of numbers a1, a2, ..., an, if we move the first m >= 0 numbers to the end of the seqence, we will obtain another sequence. There are totally n such sequences as the following:
a1, a2, ..., an-1, an (where m = 0 - the initial seqence)
a2, a3, ..., an, a1 (where m = 1)
a3, a4, ..., an, a1, a2 (where m = 2)
...
an, a1, a2, ..., an-1 (where m = n-1)
You are asked to write a program to find the minimum inversion number out of the above sequences.
For a given sequence of numbers a1, a2, ..., an, if we move the first m >= 0 numbers to the end of the seqence, we will obtain another sequence. There are totally n such sequences as the following:
a1, a2, ..., an-1, an (where m = 0 - the initial seqence)
a2, a3, ..., an, a1 (where m = 1)
a3, a4, ..., an, a1, a2 (where m = 2)
...
an, a1, a2, ..., an-1 (where m = n-1)
You are asked to write a program to find the minimum inversion number out of the above sequences.
Input
The
input consists of a number of test cases. Each case consists of two
lines: the first line contains a positive integer n (n <= 5000); the
next line contains a permutation of the n integers from 0 to n-1.
Output
For each case, output the minimum inversion number on a single line.
Sample Input
10
1 3 6 9 0 8 5 7 4 2
Sample Output
16
思路:依次统计a[i]前面有多少个比它大,求和就是初始化序列的逆序数个数;所有的数都在第一个数之后,那么比第一个数大的个数为n-a[1] - 1,比a[1]小的数就是a[1](关键),每次把第一个数放到最后一个位置时,逆序数增加了n-a[1]-1-a[1]了,明白了这个就好做了。
1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 #include <iomanip> 5 #include <set> 6 #include <map> 7 #include <vector> 8 #include <queue> 9 #define N 5005 10 using namespace std; 11 int a[N]; 12 int segtree[N << 2]; 13 void update(int ll, int rr, int l, int r, int p) 14 { 15 if (ll <= l && rr >= r) 16 { 17 segtree[p]++; 18 return; 19 } 20 int mid = (l + r) >> 1, pp = p << 1; 21 if (mid >= rr) 22 update(ll, rr, l, mid, pp); 23 else 24 if (mid < ll) 25 update(ll, rr, mid + 1, r, pp + 1); 26 else 27 { 28 update(ll, mid, l, mid, pp); 29 update(mid + 1, rr, mid + 1, r, pp + 1); 30 } 31 segtree[p] = segtree[pp] + segtree[pp + 1]; 32 } 33 int query(int ll, int rr, int l, int r, int p) 34 { 35 if (ll <= l && rr >= r) 36 return segtree[p]++; 37 int mid = (l + r) >> 1, pp = p << 1; 38 if (mid >= rr) 39 query(ll, rr, l, mid, pp); 40 else 41 if (mid < ll) 42 query(ll, rr, mid + 1, r, pp + 1); 43 else 44 return query(ll, mid, l, mid, pp) + 45 query(mid + 1, rr, mid + 1, r, pp + 1); 46 } 47 int main() 48 { 49 int n, i, ans, minans; 50 while (~scanf("%d", &n)) 51 { 52 memset(segtree, 0, sizeof(segtree)); 53 ans = 0; 54 for (i = 1; i <= n; i++) 55 { 56 scanf("%d", &a[i]); 57 update(a[i] + 1, a[i] + 1, 1, n, 1);//将所有数加1,除去0,线段树下标从1开始 58 if (a[i] + 1 < n)//当a[i] = n,不操作 59 ans += query(a[i] + 2, n, 1, n, 1); 60 } 61 minans = ans; 62 for (i = 1; i < n; i++) 63 { 64 ans += n - a[i] * 2 -1; 65 if (minans > ans) 66 minans = ans; 67 } 68 printf("%d ", minans); 69 } 70 return 0; 71 }