Minimum Inversion Number
题意:
给定数字序列 a1,a2,…,an 的反转数是满足 i < j 和 ai > aj 的对(ai,aj)的数量。
对于给定的数字序列 a1,a2,…,an,把该序列最前面的数移到序列最后面,就会得到一个新的序列,经过 n-1 次该操作后,我们就有一共 n 个序列,找出这些序列中的最小反转数。
输入:有多组测试数据,每组第一行给定一个整数 n ,接下来一行包含从0到n-1的n个整数的排列。
数据范围:
n <= 5000
解题思路:
线段树 or 树状数组
这题本质上是求序列中的逆序对
数,并求出所有序列中逆序对数最少的那个。之前求逆序数都是用的树状数组,这还是第一次用线段树来求。
代码:
① 线段树:
Exe.Time : 46MS | Exe.Memory : 1776K
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
using namespace std;
#define INF 0x3f3f3f3f
#define zero 1e-7
#define lowbit(x) x&(-x)
typedef long long ll;
const int N=1e5+5;
const int maxn=5e3+5;
int a[maxn], sum[maxn<<2];
void build(int l, int r, int p) {//建一棵空树
sum[p]=0;
if(l==r) return ;
int mid=(l+r)>>1;
build(l, mid, p<<1);
build(mid+1, r, (p<<1)|1);
}
void update(int l, int r, int p, int c) {
if(l==r) {
sum[p]++;
return ;
}
int mid=(l+r)>>1;
if(c<=mid) update(l, mid, p<<1, c);
else update(mid+1, r, (p<<1)|1, c);
sum[p]=sum[p<<1]+sum[(p<<1)|1];
}
int query(int l, int r, int p, int s, int t) {
if(s<=l && r<=t) return sum[p];
int mid=(l+r)>>1;
int ans=0;
if(s<=mid) ans+=query(l, mid, p<<1, s, t);
if(t>mid) ans+=query(mid+1, r, (p<<1)|1, s, t);
return ans;
//printf("a[i]=%d, ans=%d\n", s, ans);
}
int main() {
int n;
while(scanf("%d", &n)!=EOF) {
build(0, n-1, 1);
int ans=0;
for(int i=0; i<n; i++) {
scanf("%d", &a[i]);
ans+=query(0, n-1, 1, a[i], n);//区间,节点,查询区间
update(0, n-1, 1, a[i]);//区间,节点,待更新的叶节点
}
int res=ans;
for(int i=0; i<n; i++) {
ans+=n-a[i]-a[i]-1;//减去比a[i]小的(a[i]个),加上比a[i]大的(n-a[i]-1个)
res=min(res, ans);
//printf("%dans=%3d\n", i+1, ans);
}
printf("%d\n", res);
}
return 0;
}
② 树状数组:
Exe.Time : 46MS | Exe.Memory : 1764K
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
using namespace std;
#define INF 0x3f3f3f3f
#define zero 1e-7
#define lowbit(x) x&(-x)
typedef long long ll;
const int N=1e5+5;
const int maxn=5e3+5;
int a[maxn], sum[maxn], n;
void add(int x) {
while(x<=n) {
sum[x]++;
x+=lowbit(x);
}
return ;
}
int query(int x) {
int ans=0;
while(x) {
ans+=sum[x];
x-=lowbit(x);
}
return ans;
}
int main() {
while(scanf("%d", &n)!=EOF) {
memset(sum, 0, sizeof(sum));
for(int i=1; i<=n; i++) {
scanf("%d", &a[i]);
a[i]++;
}
int ans=0;
for(int i=n; i; i--) {
ans+=query(a[i]);
add(a[i]);
}
int res=ans;
for(int i=1; i<n; i++) {
int temp=query(a[i]-1);
ans-=temp;
ans+=n-1-temp;
res=min(res, ans);
}
printf("%d\n", res);
}
return 0;
}