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


    title: Minimum Inversion Number
    tags: [acm,杭电,树状数组]

    题目链接

    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
    

    题意

    给你n个数字 这些数字都是从0到n-1的,每次把第一个位置的数字移到最后一位形成一个新的序列,然后求出这些序列的逆序数,最后输出最小的逆序数。

    分析

    什么是逆序数:对于数x和y,若y的位置在x的前面并且y比x大,那么(x,y)就是一个逆序数对,

    普通方法解决:例子:

    5  4  3  6  1  2
    当输入5时,就用一个标记数组a[5]=1,(a数组初始化全部为零),然后从6开始往后遍历,当遇到a[i]==1时,说明i这个数在6之前出现过,那么6的逆序数对就增加一个。
    输入4时同理。。。。
    

    这种方法很容易想到,代码也很容易实现。两个for循环就行了,但是套路那么深,这道题怎么可能怎么简单,肯定会超时的,就得用树状数组来做了。

    设e[ ]就是这个树状数组,e数组是用来维护a数组的信息,e[i]代表是在当前情况下从1到i这个区间已经出现的数的个数,如 e[3]=2 代表的是在 [1,3]已经出现了两个数字 e[n]=k,代表的是在[1,n]已经出现的数的个数, e[n]-e[3]所代表的意思就很显然是此时大于3的已经出现的数的个数,这不就是3的逆序数嘛~~~我等凡夫俗子老半天才看懂大神的代码

    由于这道题的数据时从0到n-1的,当求出一个序列的逆序数后,把这个序列的第一个数放到最后的位置形成的新的序列,这个新的序列的逆序数和原来的逆序数是由一定的关系的:

    假设num[]数组如下  个数n=6
    1  4  3  5  0  2  这个序列的逆序数为  x
    4  3  5  0  2  1   当把1放到后面时,0的逆序数就减少了一个   但是比1 大的2 3  4  5  就成了1的逆序数
    3  5  0  2  1  4   当把4放到后面时,3,2,1,0的逆序数就各减少了一个   但是比4 大的5  就成了4的逆序数
    所以可推出如下规律: 新的逆序数t=x-num[1] + n-1-num[i]
    x-num[1]: 把第一个数字放到后面,比num[1]小的数字的逆序数减少了,
    + n-1-num[i]:把第一个数字放到后面,比num[1]大的数字就构成num[1]的逆序数
    

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    using namespace std;
    
    const int N=5010;
    
    int n,arr[N],num[N];
    
    int lowbit(int x)
    {
        return x&(-x);
    }
    
    void update(int id,int x)
    {
        while (id<=N)
        {
            arr[id]+=x;
            id+=lowbit(id);
        }
    }
    
    int Sum(int id)
    {
        int ans=0;
        while (id>0)
        {
            ans+=arr[id];
            id-=lowbit(id);
        }
        return ans;
    }
    int main()
    {
        //freopen("1.txt","r",stdin);
         
        while (scanf("%d",&n)!=EOF)
        {
            memset(arr,0,sizeof(arr));
            int i,ans=0;
            for (i=1; i<=n; i++)
            {
                scanf("%d",&num[i]);
                ans+=Sum(n+1)-Sum(num[i]+1);//当前的逆序数个数
                update(num[i]+1,1);
            }
            int tmp=ans;
            for (i=1; i<=n; i++)
            {
                tmp+=n-1-num[i]-num[i];
                ans=min(ans,tmp);
            }
                printf("%d
    ",ans);
             
        }
        return 0;
    }
    
    
  • 相关阅读:
    redis 用scan 代替keys 解决百万数据模糊查询超时问题
    集成spring-ldap
    IDEA报Unable to save settings: Failed to save settings. Please restart IntelliJ IDEA随后闪退
    struts2响应文件 struts2下载txt
    QRCodeUtil 二维码生成 解析 带图片与不带图片的二维码
    java 手机号正则表达式 截止2019年6月最新
    Java遍历Map对象的四种方式效率对比
    SpringCloud Alibaba系列(二) Nacos高可用和持久化
    SpringCloud Alibaba系列(二) Nacos配置中心-分类配置
    SpringCloud Alibaba系列(二) Nacos使用
  • 原文地址:https://www.cnblogs.com/dccmmtop/p/6708375.html
Copyright © 2011-2022 走看看