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;
    }

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

  • 相关阅读:
    杜教筛
    linux运维好书推荐:《高性能Linux服务器构建实战Ⅱ》热销中,附实例源码下载
    分布式监控系统ganglia配置文档
    基于Web应用的性能分析及优化案例
    一次Linux系统被攻击的分析过程
    Keepalived中Master和Backup角色选举策略
    linux运维好书《高性能Linux服务器构建实战Ⅱ》已出版发售,附封面照!
    并行分布式运维工具pdsh
    安全运维之:Linux系统账户和登录安全
    安全运维之:文件系统安全
  • 原文地址:https://www.cnblogs.com/JMDWQ/p/2587630.html
Copyright © 2011-2022 走看看