zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    CSUST 8.4 早训
    CSUST 8.5 早训
    hdu1542 Atlantis 线段树--扫描线求面积并
    hdu1540 Tunnel Warfare 线段树/树状数组
    hdu1535 Invitation Cards 最短路
    hdu1358 Period KMP
    SQL Server 向数据库中创建表并添加数据
    初次实践数据库--SQL Server2016
    hdu1301 Jungle Roads 最小生成树
    hdu1281 棋盘游戏 二分图最大匹配
  • 原文地址:https://www.cnblogs.com/fqfzs/p/9892396.html
Copyright © 2011-2022 走看看