zoukankan      html  css  js  c++  java
  • hdu 1394 Minimum Inversion Number (树状数组求逆序对)

    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的序列。求1..n,2..n..1,3..n..12,4..n..1..3,...这n种排列最小的逆序数。

    1、树状数组

    写这道题更多地是给自己一个树状数组的模板。建立在sum数组上的lowbit,add,getsum三个操作。

    2、求逆序数

    在初始全为0的长为n的数组上的操作。结构体排序。若有重复的值,注意排序的比较方式,应当是序号较大的排在后面,避免被记入逆序数。

    3、本题技巧

    0..n-1这n个数的序列。若第一个数为a,将其放至最后一位,则逆序数减少a,增加n-1-a,从而看做增加n-1-2a。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    using namespace std;
    
    const int maxn=5000;
    const int inf=1000000000;
    
    int a[maxn+10];
    
    struct tnode
    {
        int num;
        int seq;
        bool operator<(const tnode& y) const
        {
            return num<y.num;
        }
    };
    tnode node[maxn+10];
    
    int sum[maxn+10];
    
    inline int lowbit(int x)
    {
        return x&-x;
    }
    
    inline void add(int x,int val,int n)//向1..n序列的x位置加上val
    {
        for(int i=x;i<=n;i+=lowbit(i))
            sum[i]+=val;
    }
    
    inline int getsum(int x)//1..x的和
    {
        int ret=0;
        for(int i=x;i;i-=lowbit(i))
            ret+=sum[i];
        return ret;
    }
    
    int main()
    {
        int n;
        while(scanf("%d",&n)!=EOF)
        {
            for(int i=1;i<=n;i++)
                scanf("%d",a+i);
            for(int i=1;i<=n;i++)
                node[i]=(tnode){a[i],i};
            sort(node+1,node+n+1);
            int ans0=0;
            memset(sum,0,sizeof(sum));
            for(int i=n;i>=1;i--)
            {
                ans0+=getsum(node[i].seq);
                add(node[i].seq,1,n);
            }
            int ans=ans0;
            for(int i=1;i<n;i++)
            {
                ans0=ans0+n-1-2*a[i];//0..n-1的排列逆序数规律
                ans=min(ans,ans0);
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    建站随手记:about server stack
    【个人申明】主要发表平台迁至简书和公众号
    每日一问:Android 消息机制,我有必要再讲一次!
    每日一问:View.getContext() 的返回一定是 Activity 么?
    每日一问:Android 滑动冲突,你们都是怎样处理的
    每日一问:谈谈 SharedPreferences 的 apply() 和 commit()
    每日一问:浅谈 onAttachedToWindow 和 onDetachedFromWindow
    每日一问:到底为什么属性动画后 View 在新位置还能响应事件
    百万级日活 App 的屏幕录制功能是如何实现的
    每日一问:不一样的角度吐槽下 DataBinding
  • 原文地址:https://www.cnblogs.com/acboyty/p/9745807.html
Copyright © 2011-2022 走看看