「Wdsr-2」Pour Water - 题解
子任务 1
- 暴力,挨个算出每两杯水混合后的温度,
sort一遍求k 大。 - 期望得分:
10 分。
子任务 2
- 贪心
- 期望得分:
40 分。
结论是:混合后温度最高的一杯水,混合前的两杯中必定有原先温度最高的一杯。
证明
贪心参考代码(By chenxinyang2006):
#include <cstdio>
#include <algorithm>
#define ll long long
int n,k;
int cnt;
struct node{
ll a,c;
}Q[1000005],now[1000005];
bool cmp(node a,node b){
if(a.c == b.c) return a.a < b.a;
return a.c > b.c;
}
int main(){
scanf("%d%d",&n,&k);
for(int i = 1;i <= n;i++){
scanf("%lld%lld",&Q[i].a,&Q[i].c);
}
std::sort(Q + 1,Q + n + 1,cmp);
double mx = 0,tmp;
for(int i = 2;i <= n;i++){
tmp = (Q[1].a * Q[1].c + Q[i].a * Q[i].c) * 1.0 / (Q[1].a + Q[i].a);
if(mx < tmp) mx = tmp;
}
printf("%.3f\n",mx);
return 0;
}
综合以上算法,可以获得
子任务 3
- 正解
- 期望得分:
100 分
思路
注意到是求
- 通过求
1 大,2 大,3 大 …… 直到求出k 大。 - 二分答案,然后数个数。
注意到
设当前二分的值为
显然,
将含
发现两边的值都是确定的,我们分别算出。
然后就是这样一个问题了:
给出两个长度为
这是一个经典问题,比较简单的一个做法是将两个序列分别排序,然后使用双指针法
时间复杂度:
参考代码
#include <cstdio>
#include <algorithm>
using namespace std;
#define ll long long
#define eps 1e-3
int n;
ll k;
int a[100005],c[100005];//a 毫升,c 温度
double p[100005],q[100005];
bool cmp(double a,double b){
return a < b;
}
int check(double v){
ll tot = 0;
for(int i = 1;i <= n;i++){
double x = a[i] * 1.0 * c[i],y = v * 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);
int j = 0;
for(int i = 1;i <= n;i++){
while((q[j + 1] - p[i]) < eps && j + 1 <= n) j++;
tot += j;
}
return (tot / 2 < k);
}
int main(){
scanf("%d%lld", &n, &k);
for(int i = 1;i <= n;i++){
scanf("%d%d",&a[i],&c[i]);
}
double l = 1,r = 1000000000,mid;
while((r - l) > eps){
mid = (l + r) / 2;
if(check(mid)){
r = mid;
}
else{
l = mid;
}
}
printf("%.3f\n", l);
return 0;
}