hdu1394(對循環數列求最小逆序數)

題意:給你一個數組,求出這個數組的全部循環移位狀態的逆序數,求出最小值ios

解題思路:對於一個數組中求逆序數是比較簡單的,其實就是把每一個數前面的大於它的數的數目加起來就是逆序數了。
利用樹狀數組加速的話,就是把沒輸入一個數就先查詢再更新,查詢出的值是比當前數要小或相等的 且 在當前數前面的數的數目,假如前面有i個數,查詢值爲k,則當前數前面的比當前數大的數目爲i-k,把這些值加起來就是逆序數了。數組

對於每循環左移一位,假設當前被移位的值爲a[i],上一狀態的逆序數爲mm,數的總數爲n,則
移位後,a[i]前面的比它大的數的數目 = n - 查詢(a[i])
移位前,a[i]後面的比它小的數的數目 = 查詢(a[i]-1)
最新狀態的逆序數 = mm + 移位後,a[i]前面的比它大的數的數目 - 移位前,a[i]後面的比它小的數的數目ide

15msC++代碼spa

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
using namespace std;
const int NUM = 5005<<2;
int cc[ NUM ];
int nn;
int lowbit(int i)//尋找過程
{
return i&(-i);
}
void update(int i,int num)//更新,把1--i的全部值都加上num!!!!
{
while(i>0 && i<=NUM)//將0的狀況徹底排除,其中nn是記錄的數據的上限
{
cc[i]=cc[i]+num;//其中cc是上傳記錄的數組
i=i+lowbit(i);
}
}
int sum(int i)//查詢1--i的和?
{
int t=0;
while(i>0&& i<=NUM)
{
t=t+cc[i];
i=i-lowbit(i);
}
return t;
}
void init()
{
memset(cc, 0, sizeof(cc));
}
int main()
{
int i,x,ans,a[5005];
while(scanf("%d",&nn)!=EOF)
{
init();
ans = 0;
for(i = 0; i<nn ;i++)
{
scanf("%d",&a[i]);
a[i]++;
ans = ans + i - sum(a[i]);
update(a[i],1);
}
int mm = ans;
for(i = 0; i<nn ;i++)
{
int tmp = sum(a[i] - 1);
mm = mm + nn - tmp - sum( a[i] ) ;
ans = min(ans,mm);
}
printf("%d\n",ans);
}
return 0;
}
相關文章
相關標籤/搜索