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

    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

    题意:
    题意:0~n-1且不一定有序排列的数字串,不断的将第一个数字放到数字串的最后,可以得到n个不同的数字串。每一个数字串都有一个逆序数,求n个数字串中最小的逆序数。
    思路:
    很简单的线段树,树状数组也可以做,把数拿下来每次往线段树里面查,或者往一个新数组里面插,就xjb些就行了

    做这道题的时候初识线段树,竟然敲了一大段代码手写了一个for循环,坑爹的是竟然 842Ms 水过了
    后来for循环写了一下 102Ms就过了 —– 菜鸡如我
    仔细学习了一下线段树之后理解了线段树的区间查询再写了一次 42 Ms 过了 在这里写一下心得体会,
    线段树的区间查询操作之所以是O(lg(n))的复杂度,完全是因为分治,每次都查询一半,如果每一个都遍历一次的话,
    跟for循环就一模一样了,而且百度学习线段树的时候还学习到了懒标记的使用,也是线段树的一大重点,能够很好的降低时间复杂度,值得学习

    ———————————————————-AC code—————————————

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    #define lson l,mid,rt<<1
    #define rson mid+1,r,rt<<1|1
    using namespace std;
    const int maxn = 6000+5;
    struct segtree{
        int l,r;
        int sum;
    }ss[maxn<<2];
    
    int v[maxn];
    
    void build(int l,int r,int rt ) {
        ss[rt].l = l,ss[rt].r = r;
        if ( ss[rt].l == ss[rt].r ) { ss[rt].sum = 0; return;}
        int mid = (l+r)>>1;
        build(lson); build(rson);
        ss[rt].sum = 0;
    }
    
    void update(int l,int r,int rt){
        if ( ss[rt].l == ss[rt].r ) { ss[rt].sum++; return; }
        int mid = (ss[rt].l+ss[rt].r)>>1;
        if ( mid >= r ) update(l,r,rt<<1);
        else update(l,r,rt<<1|1);
        ss[rt].sum = ss[rt<<1].sum + ss[rt<<1|1].sum;
    }
    
    int query(int l,int r,int rt){
        if ( ss[rt].l == l && ss[rt].r == r ){
            return ss[rt].sum;
        }
        int mid = (ss[rt].l+ss[rt].r)>>1; int s = 0;
        if ( mid >= r ) {
            s += query(l,r,rt<<1);
        } else if ( mid < l ) {
            s += query(l,r,rt<<1|1);
        } else {
            s += query(l,mid,rt<<1);
            s += query(mid+1,r,rt<<1|1);
        }
        return s;
    }
    
    int main(){
        int t;
        while(~scanf("%d",&t)){
            build(1,t,1);
            int sum = 0;
            for (int i = 1;i<=t;i++) {
                scanf("%d",&v[i]); v[i]++;
                if ( v[i] != t )
                    sum += query(v[i]+1,t,1);
                update(v[i],v[i],1);
            }
            int minn = sum;
            for (int i = 1;i<=t;i++){
                sum = sum + t - 2*v[i] + 1;
                minn = min(minn,sum);
            }
            printf("%d
    ",minn);
        }
        return 0;
    }
    

    其实树状数组也可以实现

    ——————————————- AC code ————————————————-

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define debug puts("ok!");
    using namespace std;
    //typedef long long ll;
    const int maxn = 50000+5;
    
    int bit[maxn],t;
    
    int lowbit(int pos){
        return (pos & (-pos));
    }
    int query(int pos){
        int ret = 0;
        while(pos > 0){
            ret += bit[pos];
            pos -= lowbit(pos);
        }
        return ret;
    }
    void update(int pos)
    {
        while(pos<=t){
            bit[pos] ++;
            pos += lowbit(pos);
        }
    } 
    
    int v[maxn];
    
    int main(){
        while(cin>>t){
            int sum = 0;
            memset(bit,0,sizeof(bit));
            for (int i = 1;i<=t;i++) {
                scanf("%d",&v[i]);    v[i]++;
                sum += query(t) - query(v[i]);
                //printf("%d
    ",query(t));
                update(v[i]);
            }
            //printf("%d
    ",sum);
            int minn = sum;
            for (int i = 1;i<=t;i++){
                sum = sum + t - 2*v[i] + 1;
                minn = min(minn,sum);
            }
            printf("%d
    ",minn);
        }
        return 0;
    } 
  • 相关阅读:
    【javascript基础】JS计算字符串所占字节数
    mysql设置有外键的主键自增及其他
    spring AOP简单实现代码存放
    Dockerfile指令及docker的常用命令
    ubuntu 16.04 jenkins pipline的实现 最终docker启动服务
    ubuntu16.04 docker安装
    ubuntu16.04 nginx安装
    ubuntu14.04 spring cloud config server + gradle搭建
    ubuntu14.04 python2.7安装MySQLdb
    flask初次搭建rest服务笔记
  • 原文地址:https://www.cnblogs.com/Nlifea/p/11745976.html
Copyright © 2011-2022 走看看