标签:
/*****************************************************************************************************************
题意:给你N个排列不规则的数,任务是把它从小到大排好,每次只能交换相邻两个数,交换一次的代价为两数之和,求最小代价
注意 每次交换 都必须只能交换相邻的2个
思路:对于当前数X,我们如果知道前面比它大的数有多少,假设为K,那么有部分代价是确定的,那就是K*X;
然后还得加上比它大的那些数之和,这就是当数列到X为止,排好所需要的最小代价。
**********************************************************************************************************************/
#include<iostream>
#include<cstring>
using namespace std;
const int maxn=100001;
struct node
{
int cnt;
__int64 sum;
}tree[maxn];
int n;
int lowBit(int x)
{
return x&(-x);
}
void modify(int x,int y,int t)
{
while(x<=n)
{
tree[x].sum+=y;
tree[x].cnt+=t; //tree[].cnt来保存是否出现过a
x+=lowBit(x);
}
}
__int64 query_cnt(int x) //比x小的数的个数
{
__int64 sum=0;
while(x>0)
{
sum+=tree[x].cnt;
x-=lowBit(x);
}
return sum;
}
__int64 query_sum(int x) //比x小的所有数之和
{
__int64 sum=0;
while(x>0)
{
sum+=tree[x].sum;
x-=lowBit(x);
}
return sum;
}
int main()
{
while(~scanf("%d",&n))
{
int a;
__int64 ans=0;
memset(tree,0,sizeof(tree));
for(int i=1;i<=n;i++)
{
scanf("%d",&a);
modify(a,a,1); //以a为下标更新数组
__int64 k1=i-query_cnt(a); //k1为前i个数比a大的数的个数
if(k1!=0)
{
__int64 k2=query_sum(n)-query_sum(a); //目前所有数的和-目前所有比a小的数的和,为比a大的数的和
ans+=k1*a+k2; //调换a所需的时间
}
}
printf("%I64d\n",ans);
}
system("pause");
return 0;
}
标签:
原文地址:http://www.cnblogs.com/sober-reflection/p/3d228fc2288e72e43b2fdeccb550286f.html