Minimum Inversion Number
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 25092 Accepted Submission(s): 14816
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.
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
第一题线段树题。
学习https://www.cnblogs.com/ziyi--caolu/archive/2013/01/15/2860768.html
题意:给出一列数,每次把最前面一个移动最后面,都是一个新的序列,要求计算最小的逆序数并输出。
题解:在输入的时候计算线段树中有多少是比当前的数大的,表示当前序列中由该数组成逆序数,用a[i]来保存,全部输入完之后就获得总的逆序数。然后开始把前面的的数一个个移到最后面,每次计算这个序列的逆序数(用a[i]来实现,代码里注释了),并更新一下最小逆序数。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 5005 4 struct node 5 { 6 int l,r; 7 int num; 8 }tree[4*N]; 9 void creat(int i,int l,int r) { 10 int mid=(l+r)/2; 11 tree[i].l=l; 12 tree[i].r=r; 13 tree[i].num=0; 14 if(l==r) { 15 return ; 16 } 17 creat(i*2,l,mid); 18 creat(i*2+1,mid+1,r); 19 } 20 void update(int i,int k) { 21 if(tree[i].l==k&&tree[i].r==k) { 22 tree[i].num=1; 23 return ; 24 } 25 int mid=(tree[i].l+tree[i].r)/2; 26 if(k<=mid) 27 update(i*2,k); 28 else 29 update(i*2+1,k); 30 tree[i].num=tree[i*2].num+tree[i*2+1].num; 31 } 32 int getsum(int i,int k,int n) {//统计线段树中大于k的有多少个 33 if(k<=tree[i].l&&tree[i].r<=n) { 34 return tree[i].num; 35 } else { 36 int mid=(tree[i].l+tree[i].r)/2; 37 int sum1=0,sum2=0; 38 if(k<=mid) 39 sum1=getsum(i*2,k,n); 40 if(n>mid) 41 sum2=getsum(i*2+1,k,n); 42 return sum1+sum2; 43 } 44 } 45 int a[N]; 46 int main() { 47 int n; 48 while(~scanf("%d",&n)) 49 { 50 memset(a,0,sizeof(a)); 51 creat(1,0,n-1);int ans=0; 52 for(int i=0;i<n;i++) 53 { 54 scanf("%d",&a[i]); 55 ans+=getsum(1,a[i]+1,n-1);//每次统计大于该数的有多少个 56 update(1,a[i]);//插入,更新结点 57 } 58 int minn=ans;//把全部输入完后,还没有移动过的逆序数赋给minn 59 for(int i=0;i<n;i++) 60 { 61 ans=ans+n-1-a[i]-a[i];//这里的a[i]表示可以和a[i]组合逆序的对数,每次把最前面的数移动最后面,就相当于 62 minn=min(minn,ans);//有a[i]对逆序不能成立了,但相应的增加了n-1-a[i]对逆序 63 } 64 printf("%d\n",minn); 65 } 66 return 0; 67 }
原文地址:https://www.cnblogs.com/fqfzs/p/9892396.html