一、内容

题意:给定0-N-1的乱序序列,从这个序列可以形成n-1中序列,即每次移动第一个元素到最后,生成一个新的序列,然后又从这个新序列的第一个移动到最后又生成新的。求这些序列中逆序对最少的数量

二、思路


  • 由于题目是从0开始,所以全部进行+1操作
  • 叫你求n次逆序对,找出最小的那一次。
  • 把第一个数移到后面的话,逆序对的个数会增加比这个数大的个数
  • 减少比这个数小的个数。用树状数组求一下就可以了。

三、代码

#include <cstdio>
#include <cstring>
#define min(a, b) ((a) > (b) ? (b) : (a))
const int maxn = 5e3 + 5;
int n, cnt[maxn], num[maxn << 1], ans, minN = 0;

void update(int x, int v) {
for (int i = x; i <= n; i += i & (-i)) {
cnt[i] += v;
}
}

int query(int x) {
int ans = 0;
for (int i = x; i >0; i -= i & (-i)) {
ans += cnt[i];
}
return ans;
}
int main() {
while (scanf("%d", &n) != EOF) {
memset(cnt, 0, sizeof(cnt));
for (int i = 1; i <= n; i++) {
scanf("%d", num + i);
num[i]++;
}
minN = 0x3f3f3f3f;
ans = 0;
for (int i = n; i > 0; i--) {
update(num[i], 1);
ans += query(num[i] - 1);
}
for (int i = 1; i < n; i++) {
//ans = ans + query(n) - query(num[i]) - query(num[i]);
ans = ans + query(n) - query(num[i]) - query(num[i] - 1);
minN = min(minN, ans);
}
printf("%d\n", minN);
}
return 0;
}