zoukankan      html  css  js  c++  java
  • 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
     

    【题意】给出n个数,求其在第一个数到最后一个的过程中,最小的逆序数是多少

    【思路】建立一颗空树,在插入每个数的时候,统计这个数前面有多少数大于他,当a[i]由第一个变为最后一个时,要加上a[i]后面大于a[i]的数的个数,有n-1-a[i]个,要减去a[i]后面小于a[i]的数的个数,有a[i]个(注意i是从0开始的)

    #include<iostream>
    #include<string.h>
    #include<stdio.h>
    using namespace std;
    const int N=5005;
    struct node
    {
        int l,r;
        int num;
    
    }tree[N*4];
    void build(int k,int l,int r)//建空树
    {
        int mid=(l+r)/2;
        tree[k].l=l;
        tree[k].r=r;
        tree[k].num=0;
        if(l==r) return ;
        build(k*2,l,mid);
        build(k*2+1,mid+1,r);
    }
    void updata(int k,int c)//插入
    {
        if(tree[k].l==c&&tree[k].r==c)
        {
            tree[k].num=1;
            return ;
        }
        int mid=(tree[k].l+tree[k].r)/2;
        if(c<=mid)
            updata(k*2,c);
        else updata(k*2+1,c);
        tree[k].num=tree[k*2].num+tree[k*2+1].num;
    }
    int get_sum(int k,int c,int n)//统计
    {
        if(c<=tree[k].l&&tree[k].r<=n) return tree[k].num;
        else
        {
            int mid=(tree[k].l+tree[k].r)/2;
            int sum1=0,sum2=0;
            if(c<=mid)
                sum1=get_sum(k*2,c,n);
            if(n>mid)
                sum2=get_sum(k*2+1,c,n);
            return sum1+sum2;
        }
    }
    
    
    int main()
    {
        int n;
        while(scanf("%d",&n)>0)
        {
            int a[N];
            build(1,0,n-1);
            int ans=0;
            for(int i=0;i<n;i++)
            {
                scanf("%d",&a[i]);
                ans+=get_sum(1,a[i]+1,n-1);
    //每输入一个数时,检验一下先他输入的并比他大的数的个数,对于前面比他大的数来说,他是他们的逆序数 updata(
    1,a[i]); } int minx=ans; for(int i=0;i<n;i++) { ans=ans+n-2*a[i]-1; //当a[i]由第一个变为最后一个时,要加上a[i]后面大于a[i]的数的个数,有n-1-a[i]个,要 if(ans<minx) //减去a[i]后面小于a[i]的数的个数,有a[i]个(注意i是从0开始的) minx=ans; } printf("%d ",minx); } return 0; }
    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    const int N=100000+10;
    int a[N],b[N],c[N],ans[N];
    int n,cnt,sum;
    int lowbit(int x)
    {
        return x&(-x);
    }
    int query(int x)
    {
        int res=0;
        x++;
        while(x<=n)
        {
            res+=c[x];
            x+=lowbit(x);
        }
        return res;
    }
    void update(int x)
    {
        while(x)//对在他前且比他小的数,逆序数加1;
        {
            c[x]++;
            x-=lowbit(x);
        }
    }
    int main()
    {
        while(~scanf("%d",&n))
        {
            memset(a,0,sizeof(a));
            memset(c,0,sizeof(c));
            int sum=0;
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&a[i]);
                update(a[i]+1);
                sum+=query(a[i]+1);
            }
            int tmp=0,s=sum;
            for(int i=1;i<=n;i++)
            {
                tmp=sum-a[i]+(n-a[i]-1);
                sum=tmp;
                if(tmp<s)
                    s=tmp;
            }
            printf("%d
    ",s);
        }
        return 0;
    }
  • 相关阅读:
    Go实现线程池
    Go语言工程结构
    Go语言示例-函数返回多个值
    Go语言参数中的三个点是干什么的
    go语言示例-Timer计时器的用法
    Go语言的类型转化
    iOS 修改通讯录联系人地址(address)崩溃原因分析
    tableview小结-初学者的问题
    Objective-C总Runtime的那点事儿(一)消息机制
    论坛源码推荐(11.6):iPhone6/6 plus屏幕适配Demo,Java代码转Objective-C
  • 原文地址:https://www.cnblogs.com/iwantstrong/p/6032063.html
Copyright © 2011-2022 走看看