C - Minimum Inversion Number
Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u
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
1 //线段树专题解题。 2 //其实一开始没想通,后来手动模拟了一下整个树建立的过程就全部清楚了。 3 //详细AC代码在下面:
1 #include"iostream" 2 #include"algorithm" 3 #include"cstdio" 4 #include"cstring" 5 #include"cmath" 6 #define max(a,b) a>b?a:b 7 #define min(a,b) a<b?a:b 8 #define lson l,m,rt<<1 9 #define rson m+1,r,rt<<1|1 10 using namespace std; 11 const int MX = 200000+10; 12 int sum[MX<<2]; 13 void PushUp(int rt) { 14 sum[rt]=sum[rt<<1]+sum[rt<<1|1]; //更新节点 父节点为子节点之和 15 } 16 17 void Build(int l,int r,int rt) { 18 sum[rt]=0; //建立一棵空树 【这里之前放在了判断里面,叶节点确实清空了,枝节点漏掉了】 19 if(r==l) return ; 20 int m=(r+l)>>1; 21 Build(lson);//建立左节点 22 Build(rson);//建立右节点 23 } 24 25 void UpData(int p,int l,int r,int rt) { 26 if(r==l) { //找到并更新目标点 27 sum[rt]++; 28 return ; 29 } 30 int m=(r+l)>>1; 31 if(p<=m) UpData(p,lson); //如果不是目标点向左右寻找 32 if(p >m) UpData(p,rson); 33 PushUp(rt);//将更新过的每个点的子节点的和更新。 34 } 35 36 int Query(int L,int R,int l,int r,int rt) { 37 if(L<=l&&R>=r) //大小超过整个范围 38 return sum[rt]; //返回总数 39 int m=(r+l)>>1; 40 int ret=0; 41 if(L<= m) ret += Query(L,R,lson); //比x[i]大的树的左值和 42 if(R > m) ret += Query(L,R,rson); //比x[i]大的树的右值和 43 return ret; 44 } 45 int x[MX]; 46 int main() { 47 int n; 48 int sums; 49 char s[2]; 50 while(~scanf("%d",&n)) { 51 sums=0; 52 Build(0,n-1,1); //【这里应该从0~n-1比较好,从1~n的话0的位置不好放在哪里了。后面也就一样了。】 53 for(int i=0; i<n; i++) { 54 scanf("%d",&x[i]); 55 sums+=Query(x[i],n-1,0,n-1,1); 56 UpData(x[i],0,n-1,1); 57 } 58 int ret=sums; 59 for(int i=0; i<n; i++) { 60 sums=sums+n-2*x[i]-1; 61 ret=min(ret,sums); 62 } 63 printf("%d\n",ret); 64 } 65 return 0; 66 }