题目概述:
给定一个序列,交换其中两个元素x,y的代价是x+y,求将一个序列变成单调不减的序列的最小代价。
题目思路:
把一个小的从后面移到前面,需要和前面所有比他大的交换,而大的移到后面则需要和后面所有比他小的交换。所以就是正着求一次每个数在当前序列的位置和倒着求一次。最后乘这个元素然后加到结果里。
当然其实就是求逆序对数,用线段树,用类似归并排序,用树状数组都可以。。。。
给定一个序列,交换其中两个元素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;
}