zoukankan      html  css  js  c++  java
  • HDOJ 1394 Minimum Inversion Number(线段树求逆序数对)

    题意:

    给定n个数,这n个数是 0 ~ n - 1 的一个组合。定义a1, a2, ..., an 中满足 i < j && ai > aj的数对(ai, aj) 为逆序数对。

    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)

    求上面n个序列中逆序数对最少的一个为多少。

    思路:

    曾经做过一个类似的题目:http://www.cnblogs.com/kedebug/archive/2012/12/22/2829473.html

    用到的是归并排序的思想。这次利用线段树求解:

    1. 初始每个区间的值为 0

    2. 逐个读取数字ai,并且记录比ai大的数的个数

    对于位移的情况则是,当ai移到末尾则:

    1. 增加了(ai, ai-1), (ai, ai-2), ... (ai, 0) 即为ai个逆序对

    2. 减少了(n-1, n-1-1), (n-1, n-1-2), ... (n-1, ai) 即为(n-1 - ai) 个逆序对

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    #define lhs l, m, rt << 1
    #define rhs m + 1, r, rt << 1 | 1
    
    const int maxn = 5010;
    int num[maxn];
    int seg[maxn << 2];
    
    void PushUp(int rt)
    {
        seg[rt] = seg[rt << 1] + seg[rt << 1 | 1];
    }
    
    void Build(int l, int r, int rt)
    {
    
    }
    
    void Update(int p, int l, int r, int rt)
    {
        if (l == r)
            ++seg[rt];
        else
        {
            int m = (l + r) >> 1;
            if (p <= m)
                Update(p, lhs);
            else
                Update(p, rhs);
            PushUp(rt);
        }
    }
    
    int Query(int beg, int end, int l, int r, int rt)
    {
        if (beg <= l && r <= end)
            return seg[rt];
    
        int m = (l + r) >> 1;
        int ret = 0;
    
        if (beg <= m)
            ret += Query(beg, end, lhs);
        if (end > m)
            ret += Query(beg, end, rhs);
    
        return ret;
    }
    
    
    int main()
    {
        int n;
        while (scanf("%d", &n) != EOF)
        {
            int sum = 0;
            memset(seg, 0, sizeof(seg));
    
            for (int i = 0; i < n; ++i)
            {
                scanf("%d", &num[i]);
                sum += Query(num[i], n - 1, 0, n - 1, 1);
                Update(num[i], 0, n - 1, 1);
            }
    
            int ret = sum;
            for (int i = 0; i < n; ++i)
            {
                sum += (n - 1 - num[i]) - num[i];
                ret = min(ret, sum);
            }
    
            printf("%d\n", ret);
        }
    }
    -------------------------------------------------------

    kedebug

    Department of Computer Science and Engineering,

    Shanghai Jiao Tong University

    E-mail: kedebug0@gmail.com

    GitHub: http://github.com/kedebug

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

  • 相关阅读:
    硬盘任性丢数据,但分布式存储一定可靠吗?
    Service的基本组成
    固定cell.imageView.image的大小
    剪贴板服务
    取得正在运行的Activity
    取得正在运行的服务
    C#.NET学习笔记1---C#.NET简介
    取得手机的网络信息
    四、cocos2dx动画Animation介绍
    C#.NET学习笔记2---C#.第一个C#程序
  • 原文地址:https://www.cnblogs.com/kedebug/p/2856621.html
Copyright © 2011-2022 走看看