題意:給你一個數組,求出這個數組的全部循環移位狀態的逆序數,求出最小值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; }