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

    线段树,维护的是区间内整数的个数,每次插入 x 时,查询在 x 的前面比小的数的个数,并计算出比 x 大的数的个数 cnt[x] ,最后将 cnt 累加,即为逆序数;

    将队首的数放到队尾后逆序数改变:n-1-a[i], a[i] 为原始序列中第 i 个数的值;

    ----------------------------------------------------------------------

    2012/7/15

    之前的代码中,cnt[i] 是记录比第 i 个数大的的在它前面出现的数的个数,第二次写发现不需要。

    # include <cstdio>
    # include <cstring>
    
    # define N 5000 + 5
    
    int n, D, inv, a[N], sum[4 * N];
    
    void update(int i)
    {
        for (; i ^ 1; i >>= 1)
            sum[i >> 1] = sum[i] + sum[i ^ 1];
    }
    
    int query(int s, int t)
    {
        int ans = 0;
    
        s += D-1, t += D+1;
        for (; s ^ t ^ 1; s >>= 1, t >>= 1)
        {
            if (~s & 0x1) ans += sum[s+1];
            if ( t & 0x1) ans += sum[t-1];
        }
    
        return ans;
    }
    
    void init(void)
    {
        int tmp;
    
        inv = 0;
        for (D = 1; D < n+2; D <<= 1) ;
        memset(sum, 0, sizeof(sum[0])*D*2+2);
        for (int i = 1; i <= n; ++i)
        {
            scanf("%d", &tmp), ++tmp;
            a[i] = tmp;
            inv += i - 1 - query(1, tmp);
            sum[D+tmp] = 1, update(D+tmp);
        }
    }
    
    void solve(void)
    {
        int Min;
    
        Min = inv;
        for (int i = 1; i < n; ++i)
        {
            inv = inv - (a[i]-1) + (n-a[i]);
            if (inv < Min) Min = inv;
        }
        printf("%d\n", Min);
    }
    
    int main()
    {
        while (~scanf("%d", &n))
        {
            init();
            solve();
        }
    
        return 0;
    }

    ----------------------------------------------------------------------

    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

    ----------------------------------------------------------------------

    # include <stdio.h>
    # include <string.h>
    
    # define N 50010
    
    int n, D;
    int sum[4 * N], cnt[N], a[N];
    
    void update(int i)
    {
        for (; i ^ 1; i >>= 1)
        {
            sum[i >> 1] = sum[i] + sum[i ^ 1];
        }
    }
    
    int query(int s, int t)
    {
        int ret;
        
        ret = 0;
        s += D-1, t += D+1;
        for ( ; s ^ t ^ 1; s >>= 1, t >>= 1)
        {
            if (~s & 0x1) ret += sum[s+1];
            if ( t & 0x1) ret += sum[t-1];
        }
    
        return ret;
    }
    
    void init(void)
    {
        int i;
        
        for (D = 1; D < n+2; D <<= 1) ;
        
        memset(sum, 0, sizeof(sum[0])*2*D+5);
        memset(cnt, 0, sizeof(cnt[0])*n+5);
        memset(a, 0, sizeof(a[0])*n+5);
        
        for (i = 1; i <= n; ++i)
        {
            scanf("%d", &a[i]);
            cnt[i] = i - 1 - query(0, a[i]);
            ++sum[a[i]+D], update(a[i]+D);
        }
    }
    
    void solve(void)
    {
        int rev, i, min;
    
        rev = 0;
        for (i = 1; i <= n; ++i)
        {
            rev += cnt[i];
        }
        min = rev;
        for (i = 1; i <= n; ++i)
        {
            rev += n-1-2*a[i];
            if (min > rev) min = rev;
        }
        printf("%d\n", min);
    }
    
    int main()
    {    
        while (~scanf("%d", &n))
        {
            init();
            solve();
        }
    
        return 0;
    }

    ----------------------------------------------------------------------

  • 相关阅读:
    how to uninstall devkit
    asp.net中bin目录下的 dll.refresh文件
    查找2个分支的共同父节点
    Three ways to do WCF instance management
    WCF Concurrency (Single, Multiple, and Reentrant) and Throttling
    检查string是否为double
    How to hide TabPage from TabControl
    获取当前系统中的时区
    git svn cygwin_exception
    lodoop打印控制具体解释
  • 原文地址:https://www.cnblogs.com/JMDWQ/p/2587630.html
Copyright © 2011-2022 走看看