SZOJ逆序对题解

逆序对

思路

设原序列为\(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;
}
上一篇:Flood Fill -----CodeForces - 1114D(区间dp)


下一篇:成为一名更好的软件工程师的简单方法