题意:
两个人分别有nnn,mmm杯糖水,第一个人的第iii杯有a[i]a[i]a[i]克糖,b[i]b[i]b[i]克水,第二个人的第iii杯有c[i]c[i]c[i]克糖,d[i]d[i]d[i]克水。现在从两个人手中各取一杯糖水混合,有nmnmnm种可能的情况,求出其中浓度第kkk大的那一杯的浓度
Solution:
不妨先考虑这样一个问题:
两个数组各取一个元素,乘积有nmnmnm种,求出其中第kkk大的结果
直接二分答案,检查二分的答案在所有的情况排名第几,即有多少(i,j)(i,j)(i,j)有
a[i]∗b[j]>mida[i]*b[j]>mid a[i]∗b[j]>mid
只需要固定iii,二分符合这个iii的jjj的数量即可,单次check的时间复杂度是O(nlogn)O(nlogn)O(nlogn)
这样只需要找到最后一个排名为kkk的数即可,总复杂度O(nlognlogr)O(nlognlogr)O(nlognlogr),rrr是二分答案的长度
按照上述的思路,我们不妨也考虑二分答案
只需要找到有多少(i,j)(i,j)(i,j)有
a[i]+c[j]a[i]+b[i]+c[j]+d[j]>mid\frac{a[i]+c[j]}{a[i]+b[i]+c[j]+d[j]}>mid a[i]+b[i]+c[j]+d[j]a[i]+c[j]>mid
注意对一杯糖水并不是加浓度更高的糖水浓度就一定更高
此时把(2)(2)(2)改写成:
a[i]+c[j]>mid(a[i]+b[i]+c[j]+d[j])×mida[i]+c[j]>mid(a[i]+b[i]+c[j]+d[j])\times mid a[i]+c[j]>mid(a[i]+b[i]+c[j]+d[j])×mid
下标分类,有
(1−mid)×a[i]−mid×b[i]>(mid−1)×c[j]+mid×d[j](1-mid)\times a[i]-mid\times b[i]>(mid-1)\times c[j]+mid\times d[j] (1−mid)×a[i]−mid×b[i]>(mid−1)×c[j]+mid×d[j]
每次check只需要预先计算右式,排序后枚举iii在右式上二分即可了
#include<iostream>
#include<utility>
#include<vector>
#include<cstdlib>
#include<numeric>
#include<unistd.h>
#include<queue>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<set>
#include<map>
#include<stack>
#include<utility>
#include<cctype>
#include<cassert>
#include<thread>
#include<future>
#include<bitset>
#include<thread>
#include<random>
using namespace std;using ll=long long;
const int N=5e4+5,inf=0x3fffffff;
const long long INF=0x3fffffffffffffff,mod=1e9+7;#define double long doublestruct sugar {int m1,m2;
}a[N],b[N];int n,m,k;
const double eps=1e-19;int cmp(double x,double y) {if(fabs(x-y)<eps) return 0;return x-y>eps?1:-1;
}double val[N];int get_rank(double p) {for(int i=1;i<=m;i++) val[i]=(p-1)*b[i].m1+p*b[i].m2;sort(val+1,val+1+m);int ret=0;for(int i=1;i<=n;i++) {double value=(1-p)*a[i].m1-p*a[i].m2;int it=lower_bound(val+1,val+1+m,value)-val;ret+=it-1;}return ret+1;
}int main() {#ifdef stdjudgefreopen("in.txt","r",stdin);auto TimeFlagFirst=clock();#endifstd::ios::sync_with_stdio(false);std::cin.tie(nullptr);cin>>n>>m>>k;for(int i=1;i<=n;i++) {cin>>a[i].m1>>a[i].m2;}for(int i=1;i<=m;i++) {cin>>b[i].m1>>b[i].m2;}double l=0,r=1,ans=0;for(int i=1;i<=200;i++) {double mid=(l+r)/2;if(get_rank(mid)<=k) {ans=mid;r=mid;} else l=mid;}printf("%.15Lf",100*ans);#ifdef stdjudgefreopen("CON","r",stdin);std::cout<<std::endl<<"耗时:"<<std::clock()-TimeFlagFirst<<"ms"<<std::endl;std::cout<<std::flush;system("pause");#endifreturn 0;
}