題意:求逆序數,給你n個數,符合ai>aj i<j的稱爲逆序數,每一次可以把第一個數放在最後,問你一個序列裏總的逆序數最小是多少:
1.暴力解法,記錄初始序列的逆序數的總個數,每將第一個數放在最後的時候總的數目將增加n-1-a[i]個,將減少a[i]個,所以對於每個數sum += n-1-a[i]-a[i],記錄最小的sum,暴力代碼:
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 5000 + 55;
int sum[N], a[N];
int main()
{
int n;
while(~scanf("%d", &n))
{
memset(sum, 0, sizeof(sum));
for(int i=0; i<n; ++i)
{
scanf("%d", &a[i]);
}
int t = 0;
for(int i=0; i<n; ++i)
{
for(int j=i+1; j<n; ++j)
{
sum[i] += a[i]>a[j] ? 1 : 0;
}
t += sum[i];
}
int ans = 99999999;
for(int i=0; i<n; ++i)
{
t = t - a[i] + n - a[i] - 1;
ans = ans < t ? ans : t;
}
printf("%d\n", ans);
}
return 0;
}
數據較水300ms水過
2.線段樹,和暴力思想一樣,不過查詢初始逆序數sum用線段樹維護時間複雜度爲nlongn,暴力的爲n*n,代碼:
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 5000 + 50;
int sum[N<<2], a[N];
void build(int l, int r, int rt)
{
sum[rt] = 0;
if(l == r) return ;
int m = (l+r) >> 1, rtt = rt << 1;
build(l, m, rtt);
build(m+1, r, rtt+1);
}
void update(int p, int l, int r, int rt)
{
if(l == r)
{
++sum[rt];
return ;
}
int m = (r+l) >> 1, rtt = rt << 1;
if(p <= m) update(p, l, m, rtt);
else update(p, m+1, r, rtt+1);
sum[rt] = sum[rtt] + sum[rtt+1];
}
int query(int L, int R, int l, int r, int rt)
{
if(L<=l && R>=r)
{
return sum[rt];
}
int m = (l+r) >> 1, rtt = rt << 1, ans = 0;
if(L <= m) ans += query(L, R, l, m, rtt);
if(R > m) ans += query(L, R, m+1, r, rtt+1);
return ans;
}
int main()
{
int n, sumnumb;
while(~scanf("%d", &n))
{
sumnumb = 0;
build(0, n-1, 1);
for(int i=0; i<n; ++i)
{
scanf("%d", &a[i]);
sumnumb += query(a[i], n-1, 0, n-1, 1);
update(a[i], 0, n-1, 1);
}
int ans = sumnumb;
for(int i=0; i<n; ++i)
{
sumnumb += n - 1 - a[i] - a[i];
ans = ans < sumnumb ? ans : sumnumb;
}
printf("%d\n", ans);
}
return 0;
}
3.樹狀數組代碼:
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 5000 + 55;
int sumnumb[N], a[N], n;
int lowbit(int x)
{
return x&(-x);
}
void update(int pos, int add)
{
while(pos <= n)
{
sumnumb[pos] += add;
pos += lowbit(pos);
}
}
int getresult(int pos)
{
int sum = 0;
while(pos > 0)
{
sum += sumnumb[pos];
pos -= lowbit(pos);
}
return sum;
}
int main()
{
while(~scanf("%d", &n))
{
memset(sumnumb, 0, sizeof(sumnumb));
int sum = 0;
for(int i=1; i<=n; ++i)
{
scanf("%d", &a[i]);
a[i] += 1;
sum += getresult(n) - getresult(a[i]);
update(a[i], 1);
}
int ans = sum;
for(int i=1; i<=n; ++i)
{
sum += n - a[i] - a[i]+1;
ans = ans < sum ? ans : sum;
}
printf("%d\n", ans);
}
return 0;
}
注意對每個a[i]+1,若存在0,則0&-0 = 0會死循環