P6733 「Wdsr-2」间歇泉

「Wdsr-2」间歇泉

题目背景

Problem Number: 08 \textit{08} 08

题目描述

有一个间歇泉,冒出了 n n n 杯水,由于一些原因,每杯水的温度、体积不同。第 i i i 杯水的温度为 c i c_i ci,体积为 a i a_i ai

现在混合任意杯水,每混合两杯水都会得到一个新的温度值,求可能得到的第 k k k 高的温度值(不计热量损失)。

你的答案建议至少保留小数点后 3 \bm3 3 位(与标准答案之差在 1 0 − 2 \bm{10^{-2}} 102 以内即视为通过)。

输入格式

第一行一个数 n , k n,k n,k,意义如题述。

接下来 n n n 行,每行两个数 a i , c i a_i,c_i ai,ci

输出格式

一行一个实数,表示混合后的水的第 k k k 高温度。

样例 #1

样例输入 #1

5 1
1 5
4 2
5 3
2 3
1 4

样例输出 #1

4.500

提示

样例 1 说明

1 1 1 和第 5 5 5 杯水混合,得到 4.5 4.5 4.5 的温度值。可以发现,这是可能得到的最高水温。

样例 2

见题目附件中 pour2.in/pour2.ans \textbf{\textit{pour2.in/pour2.ans}} pour2.in/pour2.ans

数据规模与约定

本题采用捆绑测试。

  • Subtask   1  (10 pts) \textbf{Subtask 1}\text{ (10 pts)} Subtask 1 (10 pts) 1 ≤ n ≤ 10 1\le n\le 10 1n10
  • Subtask   2  (40 pts) \textbf{Subtask 2}\text{ (40 pts)} Subtask 2 (40 pts):保证 k = 1 k=1 k=1
  • Subtask   3  (50 pts) \textbf{Subtask 3}\text{ (50 pts)} Subtask 3 (50 pts):无特殊限制。
  • Subtask   4  (0 pts) \textbf{Subtask 4}\text{ (0 pts)} Subtask 4 (0 pts):Hack 数据。

对于 100 % 100\% 100% 的数据,有 1 ≤ n ≤ 1 0 5 1\le n\le 10^5 1n105 1 ≤ k ≤ n × ( n − 1 ) 2 1\le k\le \dfrac{n \times (n - 1)}{2} 1k2n×(n1) 1 ≤ a i , c i ≤ 1 0 9 1\le a_i,c_i\le 10^9 1ai,ci109

子任务 2/3/4 时限 2 s \text{2 s} 2 s,子任务 1 时限 1 s \text{1 s} 1 s

前置知识

对于两杯体积、温度分别为 ( a i , c i ) , ( a j , c j ) (a_i,c_i),(a_j,c_j) (ai,ci),(aj,cj) 的水,混合后温度为:

T = a i c i + a j c j a i + a j T=\dfrac{a_ic_i+a_jc_j}{a_i+a_j} T=ai+ajaici+ajcj

说明

本题数据采用 SvRan 生成,仅用时 3 min ⁡ 3\min 3min

分析

是个分数,但肯定有误差,考虑缩小误差,因为
T = a i c i + a j c j a i + a j T=\dfrac{a_ic_i+a_jc_j}{a_i+a_j} T=ai+ajaici+ajcj
我们二分一个温度double d,需找到现在有多少杯水温度 ≥ d \geq d d,后记录下,判断即可:
关于判断,这里写下公式:
T ≥ d → a i c i + a j c j a i + a j ≥ d → a i c i + a j c j ≥ d a i + d a j T \ge d \to \dfrac{a_ic_i+a_jc_j}{a_i+a_j} \ge d \to {a_ic_i+a_jc_j} \ge d{a_i+da_j} Tdai+ajaici+ajcjdaici+ajcjdai+daj
进一步整理得到:
a i c i − d a i ≥ d a j − a j c j a_ic_i-da_i \ge da_j-a_jc_j aicidaidajajcj
此时发现可以使用换元法替换为:
x i − y i > = y j − x j x_i-y_i>=y_j-x_j xiyi>=yjxj
左右两个值可以存在数组中,用双指针选出答案

代码

#include 
using namespace std;
const int M = 1e5+10;
const double eps = 1e-3;
int n, k;
int a[M], c[M];
double p[M], q[M];
function<bool(double,double)> cmp = [](double x, double y) {return x < y; };
void read() {
	cin >> n >> k;
	for (int i = 1; i <= n; i++) cin >> a[i] >> c[i];
}
bool check(double d) {
	int tot = 0;
	for (int i = 1; i <= n; i++) {
		double x = a[i] * 1.0 * c[i], y = d * a[i];
		p[i] = x - y, q[i] = y - x;
		if (q[i] - p[i] < eps) tot--;
	}
	sort(p + 1, p + n + 1, cmp);
	sort(q + 1, q + n + 1, cmp);
	for (int i = 1, j = 0; i <= n; i++) {
		while (q[j + 1] - p[i] < eps and j + 1 <= n) j++;
		tot += j;
	}
	tot /= 2;
	return tot < k;
}
void solve() {
	double l = 0, r = 1e11, mid,ans;
	while (r - l > eps) {
		mid = (l + r) / 2;
		if (check(mid)) ans = mid, r = mid;
		else l = mid;
	}
	printf("%.3f", ans);
}
int main() {
	read();
	solve();
	return 0;
}

代码分析

在上述分析中已说明思路,在此补充细节

if (q[i] - p[i] < eps) tot--;

不能与自己混合

	for (int i = 1, j = 0; i <= n; i++) {
		while (q[j + 1] - p[i] < eps and j + 1 <= n) j++;
		tot += j;
	}

x i − y i ≥ y j − x j → p [ i ] ≥ q [ j ] → 0 ≥ q [ j ] − p [ i ] x_i-y_i \ge y_j-x_j \to p[i] \ge q[j] \to 0 \ge q[j]-p[i] xiyiyjxjp[i]q[j]0q[j]p[i]

你可能感兴趣的:(算法)