首页 > 其他分享 >AtCoder ABC294 F - Sugar Water 2

AtCoder ABC294 F - Sugar Water 2

时间:2023-04-07 21:23:11浏览次数:66  
标签:AtCoder int res 等于 mid Sugar Water double 大于

AtCoder ABC294 F - Sugar Water 2

题意

有 \(2\) 排糖和水。

第 \(1\) 排有 \(N\) 瓶糖和 \(N\) 瓶水。糖分别有 \(A_i\) 克,水分别有 \(B_i\) 克。

第 \(2\) 排有 \(M\) 瓶糖和 \(M\) 瓶水,糖分别有 \(C_i\) 克,水分别有 \(D_i\) 克。

若要从第 \(1\) 排糖水中找到 \(A_i\) 克糖和 \(B_i\) 克水,第 \(2\) 排中找到 \(C_i\) 克糖和 \(D_i\) 克水进行混合,问排名第 \(K\) 甜的糖水的含糖量是多少。

算法

二分查找 + 二分答案

实现

主函数

令 \(x\) 为糖的质量,\(y\) 为水的质量,\(t\) 为含糖量。

首先二分答案 \(t\)。

如果知道比 大于 \(t\) 的 和 小于 \(t\) 的 和 等于 \(t\) 的 各有多少种方案,那么就可以知道 \(t\) 的排名,然后根据 \(t\) 的排名调整 \(l\) 和 \(r\) 的范围。

double l = 0, r = 1;

while(r - l > 1e-14){
	double mid = (l + r) / 2;
	int x = check(mid);	// 如果以浓度 mid 为标准,浓度大于等于 mid 的有多少种。 
	if(x >= k){
		ans = mid;
		l = mid;	// 试着寻找更大值 
	}
	else{
		r = mid;	// 寻找更小值 
	}
}

check(t) 函数

check(t) 函数要求的是如果以浓度 \(t\) 为标准,浓度大于等于 \(t\) 的有多少种。

因为 \(t = \dfrac{x}{x+y}\),所以如果知道 \(t\) 和 \(y\),就可以知道 \(x = \dfrac{t}{1-t} \times y\)。

int check(double t){	// 如果以浓度 t 为标准,浓度大于等于 t 的有多少种。
	int res = 0;
	double r = t / (1 - t);
	
	for(int i=1; i<=m; i++){
		// v[i] 存储的是第 2 排还需要多少糖才能达到 t 浓度 
		v[i] = c[i] - d[i] * r;
//相当于v[i] = c[i] - t / (1 - t) * d[i]; 
	}
	
	sort(v+1, v+m+1);
	
	for(int i=1; i<=n; i++){
		double w = a[i] - b[i] * r;
//		相当于 w = a[i] - t / (1 - t) * b[i]; 
		res += find(-w);		// 二分找 v 数组种大于等于 -w 的有多少项 
	}
	
	return res;
}

find(x) 函数

find(x) 函数是寻找 \(v\) 数组中大于等于 \(x\) 的有多少项。

首先二分查找第 \(1\) 个大于等于 \(x\) 的值在第几个位置,设为 \(res\) 。

有了 \(res\) 后,不难发现小于 \(x\) 的有 \(x-1\) 项,那么大于等于 \(x\) 的就有 \(m - (res - 1)\) 项。

int find(double x){		// 寻找 v 数组中大于等于 x 的有多少项 
	int l = 1, r = m;
/*
	如果最终发现没有大于等于 x 的值,那么 res 如果一开始设为 0 就会得到
	返回值为 m - 0 + 1的情况。因此将 res 的初始值设为 m + 1,那么最终如
	果没有寻找到将会返回 m - (m + 1) + 1,也就是 0,这样才正确。 
*/ 
	int res = m + 1;
	while(l <= r){
		int mid = (l + r) / 2;
		double pivot = v[mid];
		if(pivot >= x){
			res = mid;
			r = mid - 1;
		}
		else{
			l = mid + 1;
		}
	}
	return m - res + 1;
//	return m -(res - 1);
}

完整代码

#include <bits/stdc++.h>

using namespace std;

#define int long long

const int N = 5e4 + 10;

int n, m, k, a[N], b[N], c[N], d[N]; 

double ans, l = 0, r = 1, v[N];

int find(double x){		// 寻找 v 数组中大于等于 x 的有多少项 
	int l = 1, r = m;
/*
	如果最终发现没有大于等于 x 的值,那么 res 如果一开始设为 0 就会得到
	返回值为 m - 0 + 1的情况。因此将 res 的初始值设为 m + 1,那么最终如
	果没有寻找到将会返回 m - (m + 1) + 1,也就是 0,这样才正确。 
*/ 
	int res = m + 1;
	while(l <= r){
		int mid = (l + r) / 2;
		double pivot = v[mid];
		if(pivot >= x){
			res = mid;
			r = mid - 1;
		}
		else{
			l = mid + 1;
		}
	}
	return m - res + 1;
//	return m -(res - 1);
}

int check(double t){	// 如果以浓度 t 为标准,浓度大于等于 t 的有多少种。
	int res = 0;
	double r = t / (1 - t);
	
	for(int i=1; i<=m; i++){
		// v[i] 存储的是第 2 排还需要多少糖才能达到 t 浓度 
		v[i] = c[i] - d[i] * r;
//相当于v[i] = c[i] - t / (1 - t) * d[i]; 
	}
	
	sort(v+1, v+m+1);
	
	for(int i=1; i<=n; i++){
		double w = a[i] - b[i] * r;
//		相当于 w = a[i] - t / (1 - t) * b[i]; 
		res += find(-w);		// 二分找 v 数组种大于等于 -w 的有多少项 
	}
	
	return res;
}

signed main(){
	// 读入 
	scanf("%lld %lld %lld", &n, &m, &k);
	
	for(int i=1; i<=n; i++){
		scanf("%lld %lld", a+i, b+i);
	}
	
	for(int i=1; i<=m; i++){
		scanf("%lld %lld", c+i, d+i); 
	}
	
	while(r - l > 1e-14){
		double mid = (l + r) / 2;
		int x = check(mid);	// 如果以浓度 mid 为标准,浓度大于等于 mid 的有多少种。 
		if(x >= k){
			ans = mid;
			l = mid;	// 试着寻找更大值 
		}
		else{
			r = mid;	// 寻找更小值 
		}
	}
	
	// 输出 
	printf("%.10lf", ans * 100);
	return 0;
}

标签:AtCoder,int,res,等于,mid,Sugar,Water,double,大于
From: https://www.cnblogs.com/2huk/p/17297379.html

相关文章

  • 基于SqlSugar的开发框架循序渐进介绍(25)-- 基于SignalR实现多端的消息通讯
    基于ASP.NETCoreSignalR可以实现客户端和服务器之间进行即时通信。本篇随笔介绍一些SignalR的基础知识,以及结合对SqlSugar的开发框架的支持,实现SignalR的多端处理整合,从而实现Winform客户端,基于Vue3+ElementPlus的BS端整合,后面也可以实现对移动端的SignalR的整合通讯。适合Si......
  • AtCoder Beginner Contest 226(E,F,G)
    AtCoderBeginnerContest226(E,F,G)E(并查集)E这个题的大意是给我们一个无向图,我们可以把这些无向边变成有向边,让每一个点的入度都是\(1\),问有多少种变化方式要让有\(x\)个点的无向图,形成一棵树的边的数量是\(x-1\),但是我们需要的是每一个点的入度为\(1\),那么我们只还需要一条......
  • AtCoder Regular Contest 158 D - Equation
    题目链接原本看着式子直接晕了,觉得是高深的硬核数论,于是放弃(然后E也没想出来,sad)关键的思路在于,考虑构造由(a,b,c)->(ta,tb,tc)这样的求解方式。在看到这个做法后,会发现它很好地利用了题目齐次的性质;至于如何由齐次式想到这个做法,可能需要足够的天赋或者经验吧(悲)化简后得到\(At......
  • 【组会】water_on_floor_image & 总结
    实验场景channel1channel4文章内容用到的特征机器学习算法OnTheFeasibilityofEstimatingSolubleSugarContentUsingMillimeter-wave60GHz毫米波信号,估计水果中可溶性糖含量(SSC)的可行性RSS,表面粗糙程度,最大幅度值,峰值之间的时间,频域中的通道功率LR,RF......
  • AtCoder Beginner Contest 296
    AtCoderBeginnerContest296比赛连接好久没写题解了~~D-M<=ab题意就是给定N,M,求一个最小的数x同时满足x>=M且x=a*b(a<=N,b<=N);N,M<=1e12开始脑瘫想了二分,仔细一想很明显x不满足单调性,想了下暴力的时间复杂度巨大...纠结了一会,发现因子最大是sqrt(m),只需要枚举一下因......
  • AtCoder Beginner Contest 144
    AtCoderBeginnerContest144https://atcoder.jp/contests/abc144补一下3.23做的。D-WaterBottle分类讨论,三角函数。#include<bits/stdc++.h>#definepiacos(-1)usingnamespacestd;intmain(){inta,b,x;cin>>a>>b>>x;......
  • AtCoder Beginner Contest 296 A-E
    AtCoderBeginnerContest296A-Alternately1voidsolve(){2intn=read();3strings;4cin>>s;5intans=1;6for(inti=0;i<s.size()-1;i++){7if(s[i]==s[i+1])ans=0;8}9puts(ans>0?"Yes&......
  • AtCoder Beginner Contest 296
    AtCoderBeginnerContest296赛时代码A-Alternately//Problem:A-Alternately//Contest:AtCoder-AtCoderBeginnerContest296//URL:https://atcoder.jp/contests/abc296/tasks/abc296_a//MemoryLimit:1024MB//TimeLimit:2000ms////PoweredbyCP......
  • AtCoder Beginner Contest 153
    AtCoderBeginnerContest153https://atcoder.jp/contests/abc153这套比较简单。E-CrestedIbisvsMonster完全背包#include<bits/stdc++.h>#definelllonglongusingnamespacestd;constintN=1e3+5,M=1e4+5;lln,m,a[N],b[N],f[M*2],mx;int......
  • AtCoder Beginner Contest 296
    DM<=ab枚举。复杂度\(O(\sqrt{m})\)。C++Code#include"bits/stdc++.h"usingnamespacestd;usingi64=longlong;intmain(){ios::sync_with_stdio(false);cin.tie(nullptr);i64n,m;cin>>n>>m;if(m&......