中位数题解

中位数题解

POJ3579,,DYOJ4218

ssj我以前写过此题的题解了,但后来不小心删掉了

现在又看到这道题,准备重写一下题解

说的不甚清除,甚至可能有些\(小错误\),因为也是《年代久远》的代码了

正文

方法总体如下

  1. 二分差值(排在中间的差值)

那么,如何去check的这个差值\(M\)是否是*中位数

  1. 将原数组排序,方便后面求差

  2. 找大于\(M\)的差的个数和小于\(M\)的差的个数

  3. 如何找,就成为了一个『重要的问题』 😄

以找大于\(M\)的差的个数为例

不妨考虑,从\(i\)(1~n-1)开始,找以\(A[i]\)为被减数的差第一个大于\(M\)的位置

这个位置,是减数的位置,用这个位置与i作差,就是大于\(M\)的差的个数(以\(i\)为被减数的)

找的方法,显然也要二分
因为排序了,所以从h+1到n找减数

代码如下

h:  指上文的i,这里把找的二分封装成了一个函数
m:  指上文的M
int f1(int h, int m)
{
	int ans = h, s = h + 1, t = n;
	while (s <= t)
	{
		int k = (s + t) / 2;
		if (a[h] - a[k] < m)
			ans = k, s = k + 1;
		else
			t = k - 1;
	}
	return ans - h;
}

小于也同理

int f2(int h, int m)
{
	int ans = n + 1, s = h + 1, t = n;
	while (s <= t)
	{
		int k = (s + t) / 2;
		if (a[h] - a[k] > m)
			ans = k, t = k - 1;
		else
			s = k + 1;
	}
	return n - ans + 1;
}

把所有大于的个数加起来,小于也加起来,看它们是否小于\(C(n,2)/2\)即差的总数/2
小于,说明这个\(M\)是可行的

总代码如下

#include <bits/stdc++.h>
using namespace std;
int n, a[110000], l, r, i, tt, s1, s2;
long long mx = -1, mn = 1000000005;
int f1(int h, int m)
{
	int ans = h, s = h + 1, t = n;
	while (s <= t)
	{
		int k = (s + t) / 2;
		if (a[h] - a[k] < m)
			ans = k, s = k + 1;
		else
			t = k - 1;
	}
	return ans - h;
}
int f2(int h, int m)
{
	int ans = n + 1, s = h + 1, t = n;
	while (s <= t)
	{
		int k = (s + t) / 2;
		if (a[h] - a[k] > m)
			ans = k, t = k - 1;
		else
			s = k + 1;
	}
	return n - ans + 1;
}
bool cmp(int a, int b)
{
	return a > b;
}
int main()
{
	while (scanf("%d", &n) == 1)
	{
		for (i = 1; i <= n; i++)
		{
			scanf("%d", &a[i]);
			if (mx < a[i])
				mx = a[i];
			if (a[i] < mn)
				mn = a[i];
		}
		l = 0, r = mx - mn, tt = (n - 1) * n / 2;
		sort(a + 1, a + 1 + n, cmp);
		while (l <= r)
		{
			int m = (l + r) / 2;
			s1 = 0, s2 = 0;
			for (i = 1; i < n; i++)
				s1 += f1(i, m), s2 += f2(i, m);
			if (s1 <= tt / 2 && s2 <= tt / 2)
			{
				printf("%d\n", m);
				break;
			}
			if (s1 > tt / 2)
				r = m - 1;
			else
				l = m + 1;
		}
	}
	return 0;
}

结束了?

呃,大概也就是这样吧

以后看到有意思的或比赛的题还有\(0.114514\)%会写

@WangChunjie,有不清晰的地方记得提醒我,thanks

posted @ 2022-08-13 15:40  ssj_233  阅读(43)  评论(0编辑  收藏  举报