HDU 1394 Minimum Inversion Number (树状数组)

依旧是再练习下树状数组的使用:

题目大意:   给出N个数,这些数可以把后面的删掉然后放到最前面形成新的序列

                 可得到的N种情况,求出这N种情况哪种的逆序数最小

解题思路:   先求出第一个序列的逆序数,然后用很巧妙的办法求下一个序列的逆序数,直到全部求出

                 序列 4 5 2 1 3 6 ,此序列的逆序数为7,它等到的下一个序列为 5 2 1 3 6 4

                 看这个新序列的产生过程,首部删除4,尾部添加4

                 删除4,必然会使得这个序列的逆序数减少(4-1)个,因为4前面必定有4-1个数小于4

                 添加4,必然会使得这个序列的逆序数增加(6-4)个,因为4后面必定有6-4个数大于4

                 由此推出公式,假设移动的数为m,序列的逆序数=上一序列逆序数-(m-1)+(N-m)

                 先要离散化出来(这点似乎不需要,但是我还是离散了),因为给的数据范围就是0~n-1

<pre name="code" class="cpp">//树状数组
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
int n;
#define MAX 5010
typedef struct nano{
    int val;
    int order;
}node;
node a[MAX];
int aa[MAX];
int c[MAX];
int cmp(node a,node b){
    return a.val<b.val;
}
void update(int x){
    while(x<=n){
        c[x]++;
        x+=(x&-x);
    }
}
int sum(int x){
    int s=0;
    while(x>=1)//一定是1!0就死循环了
    {
        s+=c[x];
        x-=(x&-x);
    }
    return s;
}
int main(int argc, char *argv[])
{
   // freopen("1394.in","r",stdin);
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=1;i<=n;++i)
        {
            scanf("%d",&a[i].val);
            a[i].order=i;
        }
        /*for(int i=1;i<=n;++i)
          printf("%d ",a[i].val);*/
        sort(a+1,a+n+1,cmp);
        //printf("\n");
        for(int i=1;i<=n;++i)
            aa[a[i].order]=i;
        long long ans=0;
        /* printf("------\n");
        for(int i=1;i<=n;++i)
        {
            printf("%d ",aa[i]);
            }*/
        //printf("\n------\n");
        memset(c,0,sizeof(c));
        for(int i=1;i<=n;++i){
            update(aa[i]);
            ans+=(i-sum(aa[i]));
        }
        long long MIN=ans;
        for(int i=1;i<=n;++i){
            ans=ans-(aa[i]-1)+(n-aa[i]);
            if(ans<MIN)MIN=ans;
        }
        printf("%lld\n",MIN);
    }
    return 0;
}

至于速度上,跟前面的归并排序解得耗时一样,可能数据还是小了,没差别,但是在数据范围很大的时候,利用离散化还是很有用的,毕竟限于内存限制,不能一下子开那么大的数据空间。

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。