hdu1394Minimum Inversion Number(线段树,求最小逆序数)

Posted fqfzs

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu1394Minimum Inversion Number(线段树,求最小逆序数)相关的知识,希望对你有一定的参考价值。

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
",minn);
65     }
66     return 0;
67 }

 

以上是关于hdu1394Minimum Inversion Number(线段树,求最小逆序数)的主要内容,如果未能解决你的问题,请参考以下文章

hdu1394 [Minimum Inversion Number]

HDU 1394 Minimum Inversion Number

HDU1394 Minimum Inversion Number

hdu 1394 Minimum Inversion Number - 树状数组

[HDU1394]Minimum Inversion Number

[hdu1394]Minimum Inversion Number(树状数组)