HDU 1394:Minimum Inversion Number

来源:互联网 发布:访问网站出现 php探针 编辑:程序博客网 时间:2024/06/05 00:11

点击打开题目链接

题目意思是给出一个数n,然后给出0~n-1中不同的n的个数组成一个序列,然后每次将最后一个数放到最后一个,然后看这样一次次转换的序列中的

逆序树的最小值。

求逆序树有好多种方法:暴力法,归并排序法,树状数组法,线段树法。最近学习线段树,所以就用线段树写,其他方法后续会补上。

这里对于题目所给序列。对于第一个数x,则后面必然有x-1~0这几个数都比它小,则逆序对为x,后面的x+1~n-1都比x大是正序的,无影响。

当吧x挪到最后一位时,本来x-1~0这几个数是在x后面,则现在变成是在前面,则当前逆序数减去x对,原来的x+1~n-1都再x的前面了,则

逆序数对又增加了n-1-x个,假如当前序列逆序数为num,则将第一位x挪到最后一位,序列的逆序数变为 num - x + n - 1 - x。

则序列变换时,求逆序数的时间复杂度为线性阶O(n)。时间复杂度已经不能再减少了,这时可以通过线段树来优化求原始序列的逆序数的

时间复杂度,首先构建一个空的线段树,里面不含有任何元素,当输入一个数x[i]时,现在线段树中查找比x大的元素的个数,当前在线段

树中的元素其在序列中的下标都比x[i]对应的下标小,则查找出的元素个数,是数x[i]的逆序对数量,然后再将新元素插入线段树。


AC代码:

#include<iostream>#include<stdio.h>#define lchild left,mid,root<<1#define rchild mid+1,right,root<<1|1using namespace std;const int maxn = 5010;/**使用线段树求逆序树**/int sum[maxn<<2];int x[maxn];void push_up(int root){    sum[root] = sum[root<<1] + sum[root<<1|1];}void build(int left,int right,int root){    sum[root] = 0;   //最开始每个节点sum都是0    if(left == right)    {        return;    }    int mid = (left+right)>>1;    build(lchild);    build(rchild);}//将新输入的树插入线段树void Insert(int x,int left,int right,int root){    if(left==right)    {        sum[root]++;        return;    }    int mid = (left+right)>>1;    if(x<=mid) Insert(x,lchild);   //插入左子树    else Insert(x,rchild);         //插入右子树    push_up(root);}//当输入一个数x时,查找线段树中x~n-1范围中数的个数int query(int L,int R,int left,int right,int root){    if(L<=left && right<=R)    {        return sum[root];    }    int ans = 0;    int mid = (left+right)>>1;    if(L<=mid) ans += query(L,R,lchild);    if(R>mid) ans += query(L,R,rchild);    return ans;}int main(){    int n;    while(~scanf("%d",&n))    {        int num = 0;        build(0,n-1,1);  ///构建空的线段树        ///用线段树求逆序数        for(int i = 0; i < n; i++)        {            scanf("%d",&x[i]);            num += query(x[i],n-1,0,n-1,1);            Insert(x[i],0,n-1,1);        }        int ans = num;        for(int i = 0; i < n; i++)        {            num = num+n-1-2*x[i];            ans = min(ans,num);        }        printf("%d\n",ans);    }    return 0;}