给出一个0到n-1的全排列,可以将第一个数字移动到最后一个,求通过任意次数移动以后最小的逆序对数。
用树状数组求出初始状态的逆序对数,然后循环更新。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int c[5002];
int d[5002];
int n;
int update(int u) {
while(u <= n) {
c[u]++;
u += u & -u;
}
return 0;
}
int query(int u) {
int ans = 0;
while(u) {
ans += c[u];
u -= u & -u;
}
return ans;
}
int main() {
int i, j;
while(~scanf("%d", &n)) {
for(i = 0; i < n; i++)
scanf("%d", &d[i]);
memset(c, 0, sizeof(c));
int ans = n * n;
int l = 0;
for(i = 0; i < n; i++) {//求初始逆序对数
update(d[i] + 1);
l += i - query(d[i]);
}
ans = l;
//循环后移跟新
for(i = 0; i < n; i++) {
l = l - d[i] + n - 1 - d[i];
if(l < ans)
ans = l;
}
printf("%d\n", ans);
}
return 0;
}