zoukankan      html  css  js  c++  java
  • HDU 1394 Minimum Inversion Number (线段树&&暴力)

    Minimum Inversion Number

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
    Total Submission(s): 10477    Accepted Submission(s): 6464


    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
     
    Author
    CHEN, Gaoli
     
    Source
     
    Recommend
    Ignatius.L
     
     
    题目的意思就是说给你一个序列,求这个序列的逆序数的对数,然后将第一个元素放到最后,从而生成了一个新的序列,直到最后一个元素到第一个时停止,求生成的序列中,最少的逆序数的对数是多少。
     
    我谈谈我的做法
    1.暴力,每次找出新序列的逆序数的对数,然后看看是不是最小值,最后输出最小值即可
    但这里要点技巧,在寻找新的序列的逆序数的对数时,没有必要去扫一遍出结果。
    可以想想,因为序列的数字是从0~n-1连续的,那么当第一个数移到最后去的时候,原来比这个数大的数字变成了逆序数,比这个数小的数就不是逆序数了
    举个例子:
    3 2 4 5 
    本来 3 2是逆序数,3 4,3 5不是逆序数,当序列变成2 4 5 3时,原来的3 4变成了4 3是逆序数,2 3就不是逆序数了
     
    所以在原有的序列中比第一个元素要小的数个数为(即逆序数的对数)  low[a[i]]=a[i],所以可以推出比第一个元素要大的数的个数为up[a[i]]=n-1-a[i]
    那么新的序列中逆序数的对数是  sum=sum-low[a[i]]+up[a[i]]=sum-a[i]+(n-1-a[i])
     
    暴力的代码
     1 #include<cstdio>
     2 #include<cstring>
     3 #include<stdlib.h>
     4 #include<algorithm>
     5 using namespace std;
     6 int a[5005];
     7 int main()
     8 {
     9     int n,i,j;
    10     while(scanf("%d",&n)!=EOF)
    11     {
    12         int sum=0;
    13         for(i=0;i<n;i++)
    14         {
    15             scanf("%d",&a[i]);
    16             for(j=0;j<i;j++)
    17                 if(a[j]>a[i])
    18                     sum++;
    19         }
    20         int ans=sum;
    21         for(i=0;i<n;i++)
    22         {
    23             sum=sum-a[i]+(n-a[i]-1);
    24             if(sum<ans)
    25                 ans=sum;
    26         }
    27         printf("%d
    ",ans);
    28     }
    29     return 0;
    30 }
    View Code

    2.线段树

    同样的一开始也是要找出逆序数的对数,暴力方法是从第一个数到现在这个数扫一遍查找,线段树的方法就是用线段树去查询,会更快

    后面对新序列的逆序数对数的处理时相同的

    线段树的代码

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<stdlib.h>
     4 #include<algorithm>
     5 using namespace std;
     6 struct node
     7 {
     8     int l,r;
     9     int num;
    10     int mid()
    11     {
    12         return (l+r)>>1;
    13     }
    14 }a[5000*4];
    15 int b[5005];
    16 void btree(int l,int r,int step)
    17 {
    18     a[step].l=l;
    19     a[step].r=r;
    20     a[step].num=0;
    21     if(l==r)  return ;
    22     int mid=a[step].mid();
    23     btree(l,mid,step*2);
    24     btree(mid+1,r,step*2+1);
    25 }
    26 
    27 void ptree(int step,int vis)
    28 {
    29     a[step].num++;
    30     if(a[step].l==a[step].r)  return ;
    31     int mid=a[step].mid();
    32     if(vis>mid)
    33         ptree(step*2+1,vis);
    34     else
    35         ptree(step*2,vis);
    36 }
    37 
    38 int fintree(int step,int x,int y)
    39 {
    40     if(a[step].l==x&&a[step].r==y)
    41         return a[step].num;
    42     int mid=a[step].mid();
    43     if(x>mid)
    44         return fintree(step*2+1,x,y);
    45     else if(y<=mid)
    46         return fintree(step*2,x,y);
    47     else
    48         return fintree(step*2,x,mid)+fintree(step*2+1,mid+1,y);
    49 }
    50 int main()
    51 {
    52     int n,i,j;
    53     while(scanf("%d",&n)!=EOF)
    54     {
    55         int ans=0;
    56         btree(0,n-1,1);
    57         for(i=0;i<n;i++)
    58         {
    59             scanf("%d",&b[i]);
    60             ans+=fintree(1,b[i],n-1);
    61             ptree(1,b[i]);
    62         }
    63         int minn=ans;
    64         for(i=0;i<n;i++)
    65         {
    66             ans=ans-b[i]+(n-1-b[i]);
    67             if(minn>ans) minn=ans;
    68         }
    69         printf("%d
    ",minn);
    70     }
    71     return 0;
    72 }
    View Code
  • 相关阅读:
    Unity Shader _Time 的单位
    egg-sequelize 实现 增删改查
    Eggjs 联表查询
    Eggjs 菜单权限管理
    Eggjs 角色管理 -- 对角色树进行 增删改查
    Egg.js 实现一维的对象数组转化为树形数组
    Egg.js 中 Session 的设置和获取
    Egg.js 中 Cookie 的设置和获取
    Egg 安全机制 CSRF 的防范
    Egg middleware 中间件
  • 原文地址:https://www.cnblogs.com/clliff/p/3895053.html
Copyright © 2011-2022 走看看