本文涉及的基础知识点
P6733 「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}} 10−2 以内即视为通过)。
输入格式
第一行一个数 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 1≤n≤10。
- 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 1≤n≤105, 1 ≤ k ≤ n × ( n − 1 ) 2 1\le k\le \dfrac{n \times (n - 1)}{2} 1≤k≤2n×(n−1), 1 ≤ a i , c i ≤ 1 0 9 1\le a_i,c_i\le 10^9 1≤ai,ci≤109。
子任务 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。
P6733 「Wdsr-2」间歇泉
Cnt函数
某杯水体积a1,温度c1,a1和c1是已知数。另一杯水体积是a,温度是c,未知数。
判断合并后温度是否大于已知数v: (a1c1+ac)/(a1+a)>=v ,则 a1c1+ac >= a1v+av即 ac-av>=a1v -a1c1。
如果数据已经按ac-av排序,直接二分。注意;第i杯水和第j杯水混合。
i
≠
j
i\neq j
i=j,(i,j)和(j,i)相同,故除以2。 时间复杂度:O(logn) 求所有(a1,c1)和其它水混合的时间复杂度是n(logn)
二分类型:寻找尾端
Check(mid)函数:混合后,温度大于等于mid的杯数大于等于k。先按ac-a*v排序,在调用Cnt函数。
参数范围:[1,1e9]
精度:0.004
时间复杂度:O(logMnlogn)
可以将温度上调1000倍,二分[1,112],然后除以1000。运算过程没有误差。温度在long long范围内。
代码
核心代码
#include <iostream>
#include <sstream>
#include <vector>
#include<map>
#include<unordered_map>
#include<set>
#include<unordered_set>
#include<string>
#include<algorithm>
#include<functional>
#include<queue>
#include <stack>
#include<iomanip>
#include<numeric>
#include <math.h>
#include <climits>
#include<assert.h>
#include<cstring>
#include<list>
#include <bitset>
using namespace std;
template<class T1, class T2>
std::istream& operator >> (std::istream& in, pair<T1, T2>& pr) {
in >> pr.first >> pr.second;
return in;
}
template<class T1, class T2, class T3 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3>& t) {
in >> get<0>(t) >> get<1>(t) >> get<2>(t);
return in;
}
template<class T1, class T2, class T3, class T4 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3, T4>& t) {
in >> get<0>(t) >> get<1>(t) >> get<2>(t) >> get<3>(t);
return in;
}
template<class T = int>
vector<T> Read() {
int n;
cin >> n;
vector<T> ret(n);
for (int i = 0; i < n; i++) {
cin >> ret[i];
}
return ret;
}
template<class T = int>
vector<T> ReadNotNum() {
vector<T> ret;
T tmp;
while (cin >> tmp) {
ret.emplace_back(tmp);
if ('\n' == cin.get()) { break; }
}
return ret;
}
template<class T = int>
vector<T> Read(int n) {
vector<T> ret(n);
for (int i = 0; i < n; i++) {
cin >> ret[i];
}
return ret;
}
class CNeiBo
{
public:
static vector<vector<int>> Two(int n, const vector<pair<int, int>>& edges, bool bDirect, int iBase = 0)
{
vector<vector<int>> vNeiBo(n);
for (const auto& [i1, i2] : edges)
{
vNeiBo[i1 - iBase].emplace_back(i2 - iBase);
if (!bDirect)
{
vNeiBo[i2 - iBase].emplace_back(i1 - iBase);
}
}
return vNeiBo;
}
static vector<vector<int>> Two(int n, const vector<vector<int>>& edges, bool bDirect, int iBase = 0)
{
vector<vector<int>> vNeiBo(n);
for (const auto& v : edges)
{
vNeiBo[v[0] - iBase].emplace_back(v[1] - iBase);
if (!bDirect)
{
vNeiBo[v[1] - iBase].emplace_back(v[0] - iBase);
}
}
return vNeiBo;
}
static vector<vector<std::pair<int, int>>> Three(int n, vector<vector<int>>& edges, bool bDirect, int iBase = 0)
{
vector<vector<std::pair<int, int>>> vNeiBo(n);
for (const auto& v : edges)
{
vNeiBo[v[0] - iBase].emplace_back(v[1] - iBase, v[2]);
if (!bDirect)
{
vNeiBo[v[1] - iBase].emplace_back(v[0] - iBase, v[2]);
}
}
return vNeiBo;
}
static vector<vector<std::pair<int, int>>> Three(int n, const vector<tuple<int, int, int>>& edges, bool bDirect, int iBase = 0)
{
vector<vector<std::pair<int, int>>> vNeiBo(n);
for (const auto& [u, v, w] : edges)
{
vNeiBo[u - iBase].emplace_back(v - iBase, w);
if (!bDirect)
{
vNeiBo[v - iBase].emplace_back(u - iBase, w);
}
}
return vNeiBo;
}
static vector<vector<int>> Mat(vector<vector<int>>& neiBoMat)
{
vector<vector<int>> neiBo(neiBoMat.size());
for (int i = 0; i < neiBoMat.size(); i++)
{
for (int j = i + 1; j < neiBoMat.size(); j++)
{
if (neiBoMat[i][j])
{
neiBo[i].emplace_back(j);
neiBo[j].emplace_back(i);
}
}
}
return neiBo;
}
};
template<class INDEX_TYPE>
class CBinarySearch
{
public:
CBinarySearch(INDEX_TYPE iMinIndex, INDEX_TYPE iMaxIndex, INDEX_TYPE tol = 1) :m_iMin(iMinIndex), m_iMax(iMaxIndex), m_iTol(tol) {}
template<class _Pr>
INDEX_TYPE FindFrist(_Pr pr)
{
auto left = m_iMin - m_iTol;
auto rightInclue = m_iMax;
while (rightInclue - left > m_iTol)
{
const auto mid = left + (rightInclue - left) / 2;
if (pr(mid))
{
rightInclue = mid;
}
else
{
left = mid;
}
}
return rightInclue;
}
template<class _Pr>
INDEX_TYPE FindEnd(_Pr pr)
{
INDEX_TYPE leftInclude = m_iMin;
INDEX_TYPE right = m_iMax + m_iTol;
while (right - leftInclude > m_iTol)
{
const auto mid = leftInclude + (right - leftInclude) / 2;
if (pr(mid))
{
leftInclude = mid;
}
else
{
right = mid;
}
}
return leftInclude;
}
protected:
const INDEX_TYPE m_iMin, m_iMax, m_iTol;
};
class Solution {
public:
long long Ans(int K, vector<pair<int, long long>>& vc) {
const int N = vc.size();
for (auto& [v, c] : vc) { c *= 1000; }
auto Cmp = [&](const pair<int, int>& pr, long long mid) {return (long long)pr.first * pr.second - pr.first * mid; };
auto Check = [&](long long mid) {
sort(vc.begin(), vc.end(), [&](const pair<int, int>& pr1, const pair<int, int>& pr2) {
return Cmp(pr1, mid) < Cmp(pr2, mid); });
vector<long long> cmps(N);
for (int i = 0; i < N; i++) {
cmps[i] = Cmp(vc[i], mid);
}
long long cnt = 0;
for (const auto& pr : vc) {
const auto needMoreEqual = -Cmp(pr, mid);
auto it = lower_bound(cmps.begin(), cmps.end(), needMoreEqual);
cnt += cmps.end() - it;
cnt -= (-needMoreEqual >= needMoreEqual);//不能和自己混合
}
return cnt / 2 >= K;
};
return CBinarySearch<long long>(1, 1e12).FindEnd(Check);
}
};
int main() {
#ifdef _DEBUG
freopen("a.in", "r", stdin);
#endif // DEBUG
ios::sync_with_stdio(0); cin.tie(nullptr);
int N, K;
cin >> N >> K;
auto vc = Read<pair<int, long long>>(N);
#ifdef _DEBUG
//printf("K=%d",K);
//cout << ",s=" << s;
//Out(vc, ",vc=");
//Out(a, ",a=");
//Out(que, ",que=");
/*Out(que, "que=");*/
#endif // DEBUG
auto res = Solution().Ans(K,vc);
auto tmp = res / 1000.0;
printf("%lf\n", tmp);
return 0;
}
单元测试
int K;
vector<pair<int, long long>> vc;
TEST_METHOD(TestMethod1)
{
K = 1, vc = { {1,5},{4,2},{5,3},{2,3},{1,4} };
auto res = Solution().Ans(K,vc);
AssertEx(4500LL, res);
}
扩展阅读
我想对大家说的话 |
---|
工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。 |
学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作 |
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注 |
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。 |
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。 |
如果程序是一条龙,那算法就是他的是睛 |
失败+反思=成功 成功+反思=成功 |
视频课程
先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771
如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176
测试环境
操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。