逆序对(hdu2838)

来源:互联网 发布:ov7670 51单片机引脚图 编辑:程序博客网 时间:2024/06/03 01:16
题目概述:
给定一个序列,交换其中两个元素x,y的代价是x+y,求将一个序列变成单调不减的序列的最小代价。
题目思路:
把一个小的从后面移到前面,需要和前面所有比他大的交换,而大的移到后面则需要和后面所有比他小的交换。所以就是正着求一次每个数在当前序列的位置和倒着求一次。最后乘这个元素然后加到结果里。
当然其实就是求逆序对数,用线段树,用类似归并排序,用树状数组都可以。。。。

一开始想用treap写的,不过左旋和右旋大数据的时候老是RE,所以果断将其退化成二叉搜索树。

代码:

#include<iostream>#include<cstdlib>#include<cstdio>#include<time.h>using namespace std;struct treap{    treap *l,*r;    int v,f,s;    inline int ls()    {        return l?l->s:0;    }    inline int rs()    {        return r?r->s:0;    }};int a[100010];treap* treapinsert(treap *a,int v){    if (!a)    {        a=(treap*)malloc(sizeof(treap));        a->v=v;        a->f=rand();        a->l=0;        a->r=0;        a->s=1;    }    else if (v<=a->v)    {        a->s++;        a->l=treapinsert(a->l,v);    }    else    {        a->s++;        a->r=treapinsert(a->r,v);    }    return a;}int treaprank(treap *a,int v,int cur){    if (a&&v==a->v) return a->ls()+cur+1;    else if (a&&v<=a->v)        return treaprank(a->l,v,cur);    else if (a)        return treaprank(a->r,v,cur+a->ls()+1);    else return 0;}int main(){    srand(time(0));    int n;    cin>>n;    for (int i=1;i<=n;i++) scanf("%d",&a[i]);    long long ans=0;    treap *root=0;    for (int i=1;i<=n;i++)    {        root=treapinsert(root,a[i]);        ans+=(long long)a[i]*(i-treaprank(root,a[i],0));    }    free(root);    treap *rooot=0;    for (int i=n;i>=1;i--)    {        rooot=treapinsert(rooot,a[i]);        ans+=(long long)a[i]*(treaprank(rooot,a[i],0)-1);    }    free(rooot);    cout<<ans<<endl;}


0 0
原创粉丝点击