看板娘加载较慢请耐心等待qwq~~~

Luogu7948[✗✓OI R1] 前方之风

Luogu7948[✗✓OI R1] 前方之风

没想到这么久不见洛谷这么多题了。这是2021年11月月赛的题,蛮有意思的,在图书馆调了一晚上。

题面

给出一个长度为 \(n\) 的序列 \(a\)\(q\) 个询问,第 \(i\) 个询问给出 \(k_i\)。对于每次询问,你需要进行以下操作:
1.求出剩下的数的平均数 \(\mathit{avg}\)
2.将剩下的数中小于 \(\mathit{avg}-k_i\)的数删去。
3.重复以上两个步骤直到所有数都不会被删去。
4.输出最后会剩下几个数。

注意:询问之间是独立的,也就是说,不会真的删去那些数。

sov

force

对数组进行排序,计算前缀和,每次二分查找会被删除的数,时间复杂度\(O(nlogn + q \quad\sum_{i = 0}^{t}{logn})\),实测只差一个点不能过,但是他开了subtask。

std

我们发现,能够预处理\(x_i - x_n\)不删除数的最大\(k_i\), \(k_{imax} = \overline{x} - x_i\),这样我们就可以预处理每一段的\(k_i\)

我们再考虑每次删除一定会是从小到大删除,如果这一次不能删除,则过程终止,因此数列\(\{k\}\)应该是单调递减的,\(k_i = \min(k_{i-1},k_i)\),对于每次询问,在预处理的\(k\)数组中进行二分查询。

时间复杂度\(O(n\log{n} + q\log{n})\)

代码

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 10;
double a[MAXN], sum[MAXN], ave[MAXN];
int n, q, t;
signed main()
{
	scanf("%d", &t);
	while (t--)
	{
		scanf("%d %d", &n, &q);
		for (register int i = 1; i <= n; ++i)
			scanf("%lf", &a[i]);
		sort(a + 1, a + 1 + n);
		for (register int i = 1; i <= n; ++i)
			sum[i] = sum[i - 1] + a[i];
		ave[0] = LONG_LONG_MAX;
		for (register int i = 1; i <= n; ++i)
		{
			ave[i] = (sum[n] - sum[i - 1]) / (n - i + 1) - a[i];
			ave[i] = min(ave[i], ave[i - 1]);
		}
		while (q--)
		{
			int k;
			scanf("%d", &k);
			int tmp = (lower_bound(ave + 1, ave + n + 1, k, greater<double>()) - ave - 1);
			printf("%d ", n - tmp);
		}
		puts("");
	}
}
posted @ 2021-11-16 21:45  椎名·六花  阅读(60)  评论(1编辑  收藏  举报