标签:
题意 :求 循环序列的最小逆序数
线段树求出最初的逆序数,
吧 Num[1] 移动到 最后一位, 逆序数减少 Num【1】-1,单比Num【1】大的有 n - Num【1】个 ,又会增加 n - Num【1】个
故可快速求出 最小逆序数
#include<iostream> #include<cstdio> #include<cstring> #define lson l, m, rt<<1 #define rson m+1, r, rt << 1|1 using namespace std; const int maxn = 5000 + 31; int Sum[maxn<<2]; int Num[maxn]; void PushUp(int rt) { Sum[rt] = Sum[rt<<1] + Sum[rt<<1|1]; } void Build(int l,int r,int rt) { Sum[rt] = 0; if(l == r) { return ; } int m = (l + r) >> 1; Build(lson); Build(rson); } void UpDate(int l,int r,int rt,int val) { if(l == val && r == val) { Sum[rt] = 1; return ; } int m = (l + r) >> 1; if(val > m) UpDate(rson,val); else UpDate(lson,val); PushUp(rt); } int GetNum(int L,int R,int l,int r,int rt) { if(L <= l && r <= R) { return Sum[rt]; } int ret = 0; int m = (l + r) >> 1; if(L <= m) ret += GetNum(L,R,lson); if(R > m) ret += GetNum(L,R,rson); return ret; } int main() { int n; while(scanf("%d",&n) != EOF) { Build(1,n,1); int sum = 0; int Min = 0; for(int i = 1; i <= n; ++i) { scanf("%d",&Num[i]); Num[i]++; sum += GetNum(Num[i],n,1,n,1); UpDate(1,n,1,Num[i]); } //cout << sum <<endl; Min = sum; for(int i = 1; i < n; ++i) { sum = sum + (n - 2*Num[i] + 1); Min = min(Min,sum); } printf("%d\n",Min); } }
标签:
原文地址:http://www.cnblogs.com/aoxuets/p/4738947.html