逆序对
思路
设原序列为\(a_1,a_2,...,a_n\)
则每次操作后变为 \(a_2,a_3,...,a_n,a_1\)
那么\(\forall i>1\)且\(a_1>a_i\)(亦即\(a_1,a_i\) 在原序列中形成逆序对),这个逆序对贡献不存在,即逆序对对数减少这样的\(i\)的个数
且由于\(a_1\)变为第\(n\)个,所以\(\forall i \in [2,n]\),若\(a_i>a_1\),则会与处于第\(n\)个的\(a_i\)产生一个逆序对,即逆序对增加这样的\(i\)的个数
代码
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
using namespace std;
int n, m, tmp[5005], a[5005], b[5005];
struct Segm
{
int l, r;
int sum;
} ;
Segm sgt[20005];
void build(int x, int l, int r)
{
sgt[x].l = l;
sgt[x].r = r;
if (l + 1 == r)
{
sgt[x].sum = 0;
return ;
}
build(x << 1, l, (l + r) / 2);
build(x << 1 | 1, (l + r) / 2, r);
sgt[x].sum = sgt[x << 1].sum + sgt[x << 1 | 1].sum;
}
void add(int x, int pos, int val)
{
if (sgt[x].l + 1 == sgt[x].r)
{
sgt[x].sum += val;
return ;
}
if (pos >= sgt[x << 1].l && pos < sgt[x << 1].r)
add(x << 1, pos, val);
else
add(x << 1 | 1, pos, val);
sgt[x].sum = sgt[x << 1].sum + sgt[x << 1 | 1].sum;
}
long long calc(int x, int l, int r)
{
if (sgt[x].l >= l && sgt[x].r <= r)
return sgt[x].sum;
if (sgt[x].l >= r || sgt[x].r <= l)
return 0;
return calc(x << 1, l, r) + calc(x << 1 | 1, l, r);
}
int main()
{
while (scanf("%d", &n) == 1)
{
for (int i = 1; i <= n; i++)
scanf("%d", a + i);
memcpy(b, a, sizeof(a));
sort(b + 1, b + n + 1);
int len = unique(b + 1, b + n + 1) - b - 1;
int ans = 0x7fffffff;
build(1, 1, n + 1);
int sum = 0;
for (int i = 1; i <= n; i++)
{
int t = lower_bound(b + 1, b + len + 1, a[i]) - b;
sum += calc(1, t + 1, n + 1), add(1, t, 1);
}
ans = sum;
for (int i = 1; i < n; i++)
{
int t = lower_bound(b + 1, b + len + 1, a[i]) - b;
sum -= t - 1;
sum += n - t;
ans = min(ans, sum);
}
printf("%d\n", ans);
}
return 0;
}