对于100%的数据,1<=n<=100000,0<=Hi<=1000000。
解题思路:
输入数据较小,用冒泡算法的完全可以解决问题。
但题目中的数据庞大,冒泡算法的时间复杂度为O(n^2),对于该题只能AC 30%的数据。
所以考虑用树形数组决解问题。
对于a[j]需要移动的次数为:a[j]的逆序对数(数组a[n]中,j之前大于a[j]的个数+j之后小于a[j]的个数)。
#include <iostream> #include <cstdio> #include <cstring> using namespace std; #define N 100010 #define MAX 1000100 int C[MAX], S[MAX], b[N]; long long total[N], ans; int num[N], T, s, t, i, j; int Lowbit(int x){ return x&(x^(x-1)); } void add(int pos,int num,int *P) { while(pos <= MAX) { P[pos] += num; pos += Lowbit(pos); } } int Sum(int end,int *P) { int cnt = 0; while(end > 0) { cnt += P[end]; end -= Lowbit(end); } return cnt; } void init(){ total[0] = 0; for(i = 1; i < N; ++i){ total[i] = total[i-1] + i; } } int main() { init(); while(~scanf("%d",&T)) { memset(C,0,sizeof(C)); memset(S,0,sizeof(S)); //memset(num,0,sizeof(num)); //memset(b,0,sizeof(b)); //ans = 0; for(j = 0; j < T; j ++) { scanf("%d",&num[j]); add(num[j]+1,1,C); b[j] = j - Sum(num[j], C);//Sum(num[j],C)求的就是小于num[j]的个数,j - Sum(num[j],C)就是前j个数中大于num[j]的个数 b[j] -= Sum(num[j]+1,C) - Sum(num[j],C)-1; //去掉和num[j]相同的数的个数 } //printf("\n"); ans = 0; for(j = T-1; j > -1; --j){//反过来求第j个数右边中小于它的数的个数。 add(num[j]+1 ,1, S); b[j] += Sum(num[j] ,S);//Sum(num[j],S)求的就是小于num[j]的个数 ans += total[b[j]]; } printf("%I64d\n",ans); } return 0; }