zoukankan      html  css  js  c++  java
  • hdu 1394 Minimum Inversion Number

    题意描述:给你一个有0--n-1数字组成的序列,然后进行这样的操作,每次将最前面一个元素放到最后面去会得到一个序列,那么这样就形成了n个序列,那么每个序列都有一个逆序数,找出其中最小的一个输出!

    这题用暴力可以过,时间是125ms,最好的方法是用线段树,大概是50+ms

    不过思想是一样的,首先统计初始的逆序数,因为题目总是将第一个数已到最后,所以原来比它小的数就不是逆序了,而原来比它大成为了逆序,显然在序列

    0,1,2,3....n-1中

    比a[i]小的数的个数为a[i]

    比a[i]大的数的个数为n-a[i]+1

    每次移动之后的逆序数sum就变为了

    sum=sum-a[i]+n-a[i]-1;

    把a[1],a[2]...a[n]都移动一遍,同时记录最小的逆序数,就行了。

    暴力代码如下:

    #include<stdio.h>
    int a[5005];
    int main()
    {
     int n,sum,i,j,ans;
     while(scanf("%d",&n)!=EOF)
     {
      sum=0;
      for(i=1;i<=n;i++)
      {
       scanf("%d",&a[i]);
       for(j=1;j<i;j++)//统计初始的逆序数和
        if(a[j]>a[i])
         sum++;
      }
      ans=sum;
      for(i=1;i<=n;i++)//将所有的数都移动一遍,同时记录最小的逆序数
      {
          sum=sum-a[i]+(n-a[i]-1);
       if(ans>sum)
        ans=sum;
      }
      printf("%d
    ",ans);
     }
     return 0;
    }

    下面介绍线段树的思想,这题中线段树用来统计初始的逆序数,其余的和暴力的差不多

    先建一个空树,每输入一个数,就查询比它大的数的数目,然后更新树的value值(value是用来记录数的,每输入一个数,只要这个线段包含了这个数,value就加1),例如,序列3,2,4,1,5.逆序数,先输入3,查询得到sum=0,并让包含3的线段value都加1(也就是update(3,1)),再输入2时,查询2~5,之前只输入了3,sum=1,,之后更新update(2,1);

    下面是线段树代码:

    #include<stdio.h>
    
    struct node{
    
           int left,right;
    
           int value;//记录插入数的个数
    
    }a[5001*3];
    
    int b[5001],sum=0;
    
    void build(int s,int t,int step)//在s~t线段建树
    
    {
    
           a[step].left=s;
    
           a[step].right=t;
    
           a[step].value=0;
    
           if(a[step].left==a[step].right)
    
                  return ;
    
           int mid=(s+t)/2;
    
           build(s,mid,step*2);
    
           build(mid+1,t,2*step+1);
    
    }
    
    void query(int k,int t,int step)//在k~t查找
    
    {
    
           if(a[step].left==k&&a[step].right==t)
    
           {
    
                  sum+=a[step].value;
    
                  return ;
    
           }
    
           int mid=(a[step].left+a[step].right)/2;
    
        if(mid>=t) query(k,t,2*step);
    
           else if(mid<k) query(k,t,2*step+1);
    
           else {
    
                  query(k,mid,2*step);
    
                  query(mid+1,t,2*step+1);
    
           }
    
    }
    
    void update(int k,int step)
    
    {
    
           a[step].value++;
    
           if(a[step].left==a[step].right)
    
                  return ;
    
           int mid=(a[step].left+a[step].right)/2;
    
           if(mid>=k) update(k,2*step);
    
           else update(k,2*step+1);
    
    }
    
    int main()
    
    {
    
           int n,i,ans;
    
           while(scanf("%d",&n)!=EOF)
    
           {
    
                  sum=0;
    
                  build(0,n-1,1);
    
                  for(i=1;i<=n;i++)
    
                  {
    
                         scanf("%d",&b[i]);
    
                         query(b[i],n-1,1);
    
                         update(b[i],1);
    
                  }
    
                  ans=sum;
    
                  for(i=1;i<=n;i++)
    
                  {
    
                         sum=sum-b[i]+(n-b[i]-1);
    
                         if(ans>sum)
    
                                ans=sum;
    
                  }
    
                  printf("%d
    ",ans);
    
           }
    
           return 0;
    
    }
  • 相关阅读:
    利用guava来实现本地的cache缓存
    加减乘除工具类BigDecimalUtil
    linux使用apache发布静态html网页
    为什么从pycharm中打开的html文件会显示404?
    unittest测试框架生成可视化测试报告-BeautifulReport
    python虚拟环境迁移
    linux查看系统版本
    Webhook到底是个啥?
    钩子函数和回调函数的区别
    LookupError: "gw_lt" is not among the defined enum values
  • 原文地址:https://www.cnblogs.com/duan-to-success/p/3269382.html
Copyright © 2011-2022 走看看