/********************************************************
Copyright:Glder
Author:Glder
Date:2013-07-31 14:40:29
Destription:
1、重点理解此题中使用的公式,首先求出原始数列每个数的逆序数a[i],
相加得出该数列总逆序数sum,然后数列中的元素每左移一次,sum的变化值为d
d = n-1-a[i]-a[i];
2、通过线段树求解时注意建树时向上更新语句的用法
3、注意程序中查询语句和更新语句使用的意义和方法
********************************************************/
/***************************************************
暴力求解法
注意公式使用方法:
首先求出原始数列每个数的逆序数a[i],相加得出该数列总逆
序数sum,然后数列中的元素每左移一次,sum的变化值为d
d = n-1-a[i]-a[i];
****************************************************/
/***********************************************************
线段树求解法,仍需要利用暴力法中变化公式
************************************************************/
Copyright:Glder
Author:Glder
Date:2013-07-31 14:40:29
Destription:
1、重点理解此题中使用的公式,首先求出原始数列每个数的逆序数a[i],
相加得出该数列总逆序数sum,然后数列中的元素每左移一次,sum的变化值为d
d = n-1-a[i]-a[i];
2、通过线段树求解时注意建树时向上更新语句的用法
3、注意程序中查询语句和更新语句使用的意义和方法
********************************************************/
/***************************************************
暴力求解法
注意公式使用方法:
首先求出原始数列每个数的逆序数a[i],相加得出该数列总逆
序数sum,然后数列中的元素每左移一次,sum的变化值为d
d = n-1-a[i]-a[i];
****************************************************/
int s[5010];
int a[5010];
int main()
{
int n;
int i,j;
while(scanf("%d",&n) != EOF)
{
for(i = 0; i < n; i++)
scanf("%d",&s[i]);
int sum = 0,t;
for(i = 0; i < n; i++)
{
t = 0;
for(j = i+1; j < n; j++)
{
if(s[i] > s[j])
t++;
}
a[i] = t;
sum += t;
}
int min = sum;
for(i = 0; i < n-1; i++)
{
sum = sum - s[i] + n - 1 - s[i];
if(sum < min)
min = sum;
}
printf("%d\n",min);
}
}
/***********************************************************
线段树求解法,仍需要利用暴力法中变化公式
************************************************************/
int min(int a,int b)
{
return a<b ? a : b;
}
struct Segtree
{
int left;
int right;
int num;
}s[5010*4];
void build(int root,int l,int r)
{
s[root].left = l;
s[root].right = r;
//这一句必须放在下面if语句外面才可以,否则wa
//原因:不同于直接输入时的建树方法,此时直接在该处的根节点标记为0就可以
//如果下面的有向上更新语句的时候可以保证每个节点都可以得到更新才可以把
//该语句放到if语句中。通过此题可以充分理解建树是向上更新语句的用法
//s[root].num = 0;
if(l == r)
{
s[root].num = 0;
return ;
}
int m = (l + r) / 2;
build(root<<1,l,m);
build(root<<1|1,m+1,r);
s[root].num = s[root*2].num + s[root*2+1].num;
}
void update(int root,int pos)
{
int l = s[root].left;
int r = s[root].right;
if(l == r)
{
s[root].num++;
return ;
}
int m = (l + r)/2;
if(pos <= m)
update(root*2,pos);
else
update(root*2+1,pos);
s[root].num = s[root*2].num + s[root*2+1].num;
//这一句必须加上,才能在更新是能够更新到父节点
}
int query(int root,int a,int b)
{
int l = s[root].left;
int r = s[root].right;
if(a <= l && r <= b)
{
return s[root].num;
}
int m = (l + r) / 2;
int ans = 0;
if(a <= m)
ans += query(root*2,a,b);
if(b > m)
ans += query(root*2+1,a,b);
return ans;
}
int num[5010];
int main()
{
int n;
int i;
while(~scanf("%d",&n))
{
build(1,0,n-1);
int sum = 0;//计算该数列总逆序数
//memset(num,0,sizeof(num));
for(i = 0; i < n; i++)
{
scanf("%d",&num[i]);
sum += query(1,num[i],n-1);//查询该数,如果之前有比之大的数,则总数++
update(1,num[i]);//更新,在该数位置标记,表明该数已经存在
}
//cout<<sum<<endl;
int ans = sum;
for(i = 0; i < n; i++)
{
sum = sum + (n-1) - num[i] - num[i];
ans = min(ans,sum);
}
printf("%d\n",ans);
}
}