題目連結

題意:

給一個n個數的序列a1, a2, ..., an ,這些數的範圍是0~n-1, 可以把前面m個數移動到後面去,形成新序列:
a1, a2, ..., an-1, an (where m = 0 - the initial seqence)
a2, a3, ..., an, a1 (where m = 1)
a3, a4, ..., an, a1, a2 (where m = 2)
...
an, a1, a2, ..., an-1 (where m = n-1)
求這些序列中,逆序數最少的是多少?

樹狀陣列:

分析:c數組裡的值代表個數,下標代表等於哪個值,是按照順序排的,所以sum(n)-sum(a[i]),就能減出來比a[i]大的數值了。

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <map>
#include <algorithm>
#define LL __int64
const int maxn = +;
using namespace std;
int c[maxn], a[maxn], n; int lowbit(int x)
{
return x&(-x);
}
void add(int x,int d)
{
while(x <= n)
{
c[x] += d;
x +=lowbit(x);
}
}
LL sum(int x)
{
LL ret = ;
while(x > )
{
ret += c[x];
x -= lowbit(x);
}
return ret;
} int main()
{
int i, ans, tmp;
while(~scanf("%d", &n))
{
ans = ;
memset(c, , sizeof(c)); //不要忘了清0
for(i = ; i <= n; i++)
{
scanf("%d", &a[i]);
a[i] ++; //因為是從0到n-1的
ans += sum(n)-sum(a[i]); //貌似a[i]太大的話就不行了吧
add(a[i], ); //c數組裡的值代表個數,下標代表等於哪個值
}
tmp = ans;
for(i = ; i <= n; i++)
{
tmp += n-a[i]-(a[i]-); //是一個公式,我沒想明白為什麼
ans = min(ans, tmp);
}
printf("%d\n", ans);
}
return ;
}

歸併排序的做法:

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#define LL __int64
const int maxn = +;
using namespace std;
int n;
int sum, b[maxn], a[maxn], a2[maxn]; void merge_sort(int *A, int x, int y, int *T)
{
if(y-x>)
{
int m=x+(y-x)/;
int p=x, q=m, i=x;
merge_sort(A,x,m,T);
merge_sort(A,m,y,T);
while(p<m || q<y)
{
if(q>=y ||(p<m && A[p] <= A[q]))
T[i++] = A[p++];
else
{
T[i++] = A[q++];
sum+=m-p;
} }
for(i=x; i<y; i++)
A[i] = T[i];
}
}; int main()
{
int i;
int tmp;
while(~scanf("%d", &n))
{
sum = ;
memset(b, , sizeof(b));
for(i = ; i < n; i++) //注意這是從0開始的,因為歸併排序的原因
{
scanf("%d", &a[i]);
a2[i] = a[i];
}
merge_sort(a, , n, b);
tmp = sum;
for(i = ; i < n; i++)
{
tmp += n--a2[i]-a2[i]; //一定要注意這個是a2[]; 因為之前的a[]的順序已經改變了。還要注意這個公式
sum = min(sum, tmp); //和上一個樹狀陣列的不同是上一個a[]++了。
}
printf("%d\n", sum);
}
return ;
}