2020.10.02日常总结——二分答案算法例题小汇总(上)

这篇博客回顾了二分答案算法,通过分析P6733「Wdsr-2」间歇泉问题,阐述了如何利用二分查找结合数学方法解决水温排序问题,并介绍了喂养宠物问题,讨论了如何运用二分算法在有限食物条件下确定最大饲养数量。
摘要由CSDN通过智能技术生成

好久没有写的博客了,让我们从二分答案这个使用且神奇的算法开始重写博客吧。

P6733   「Wdsr-2」间歇泉 \color{green}{\texttt{P6733 「Wdsr-2」间歇泉}} P6733 Wdsr-2」间歇泉

[Problem] \color{blue}{\texttt{[Problem]}} [Problem]

  • n n n 杯水,每杯水的体积为 v i v_i vi,温度为 t i t_i ti,把它们两两合并,得到新的 n × ( n − 1 ) 2 \dfrac{n \times (n-1)}{2} 2n×(n1) 杯水。求新的水中第 k k k 高的温度。
  • 两杯水 i , j i,j i,j 合并后得到的水温为 t i × v i + t j × v j v i + v j \dfrac{t_i \times v_i + t_j \times v_j}{v_i+v_j} vi+vjti×vi+tj×vj

[Solution] \color{blue}{\texttt{[Solution]}} [Solution]

先二分答案 mid \texttt{mid} mid 表示第 k k k 高的水温 ≥ mid \geq \texttt{mid} mid,现在考虑 check() 函数。

改写一下那个式子:

t i × v i + t j × v j v i + v j ≥ mid t i × v i + t j × v j ≥ mid × v i + mid × v j t i × v i − mid × v i ≥ mid × v j − t j × v j \begin{aligned} \dfrac{t_i \times v_i + t_j \times v_j}{v_i+v_j}& \geq \texttt{mid} \\ t_i \times v_i+t_j \times v_j & \geq \texttt{mid} \times v_i+\texttt{mid} \times v_j \\ t_i \times v_i-\texttt{mid} \times v_i&\geq \texttt{mid} \times v_j-t_j \times v_j \end{aligned} vi+vjti×vi+tj×vjti×vi+tj×vjti×vimid×vimidmid×vi+mid×vjmid×vjtj×vj

不等式两边的值是确定的,所以我们可以提前算出,存入两个数组内。

接着,我们将它们排序,然后就可以用尺取法 O ( n ) O(n) O(n) 的做了。

时间复杂度: O ( n × log ⁡ n × log ⁡ ( max ⁡ 1 ≤ i ≤ n v i ) ) O\left(n \times \log n \times \log \left (\max\limits_{1 \leq i \leq n}v_i \right ) \right ) O(n×logn×log(1inmaxvi))

[code] \color{blue}{\texttt{[code]}} [code]

const int N=1e5+100;
const double eps=1e-3;
double l,r,mid,p[N],q[N];
int a[N],c[N],n;ll k;//含义如题 
inline bool check(double mid){
	register long long tot=0ll;
	for(int i=1;i<=n;i++){
		double x=1.0*a[i]*c[i],y=mid*a[i];
		p[i]=x-y;q[i]=y-x;//等式的左边和右边 
		if (q[i]-p[i]<eps) tot--;//自己不混自己 
	}
	sort(p+1,p+n+1);//排序 
	sort(q+1,q+n+1);//排序 
	for(int i=1,j=1;i<=n;i++){
		while (j<=n&&q[j]-p[i]<eps) j++;
		tot+=j-1;//注意应该要累加j-1 
	}
	return tot/2<k; 
}
const double inf=1e15;
int main(){
	n=read();k=read();
	for(int i=1;i<=n;i++){
		a[i]=read();c[i]=read();
	}
	l=1;r=inf;//init
	while (l+1e-6<r){
		mid=(l+r)/2.0;
		if (check(mid)) r=mid;
		else l=mid;
	}
	printf("%.5lf",l);
	return 0;
}

[Algorithm] \color{blue}{\texttt{[Algorithm]}} [Algorithm] 二分+数学+排序+尺取法。

喂养宠物 \color{green}{\texttt{喂养宠物}} 喂养宠物

[Problem] \color{blue}{\texttt{[Problem]}} [Problem]

  • n n n 个宠物可以选择,每个宠物有两个量: a i , b i a_i,b_i ai,bi,表示喂养 k k k 只宠物时,这只宠物需要 ( a i × ( k − 1 ) + b i ) (a_i \times (k-1) +b_i) (ai×(k1)+bi) 的食物。保证 a i , b i > 0 a_i,b_i>0 ai,bi>0
  • 你现在只有 m m m 的食物,问最多可以养多少只宠物。

[Solution] \color{blue}{\texttt{[Solution]}} [Solution]

因为每只宠物的食量随养的宠物的量增大而增大,所以我们可以二分。

二分养多少只宠物,算出每只宠物需要的食量,贪心选即可。

[code] \color{blue}{\texttt{[code]}} [code]

int eat[55],add[55],e[55];
int total_food,n,l,r,mid,ans;
inline bool check(int mid){
	for(int i=1;i<=n;i++)
		e[i]=eat[i]+(mid-1)*add[i];
	sort(e+1,e+n+1);//贪心选择 
	for(int i=1,tot=0;i<=mid;i++)
		if ((tot+=e[i])>total_food)
			return false;//不符题意 
	return true;//符合题意 
}
int main(){
	scanf("%d%d",&n,&total_food);
	for(int i=1;i<=n;i++)
		scanf("%d",&eat[i]);
	for(int i=1;i<=n;i++)
		scanf("%d",&add[i]);
	l=1;r=n;ans=-1;
	while (l<=r){
		mid=(l+r)>>1;
		if (check(mid)){
			ans=mid;
			l=mid+1;
		}
		else r=mid-1;
	}
	printf("%d",ans);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值