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;
}