ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

YbtOJ 「基础算法」第3章 二分算法

2022-08-14 14:02:25  阅读:188  来源: 互联网

标签:二分 code const int YbtOJ sum mid 算法 check


例题1.数列分段

二分每段和的最大值。check 时从左往右扫,如果当前段的和大于限制则新开一段。

code
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,m,a[N];
int maxn,s;
int check(int x)
{
	int cnt=1,sum=0;
	for(int i=1;i<=n;i++)
	{
		if(sum+a[i]>x) cnt++,sum=a[i];
		else sum+=a[i];
	}
	//cout<<x<<" "<<cnt<<endl;
	return cnt;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),maxn=max(maxn,a[i]),s+=a[i];
	int l=maxn,r=s;
	while(l<r)
	{
		int mid=(l+r)>>1;
		if(check(mid)<=m) r=mid;
		else l=mid+1;
	}
	cout<<l<<endl;
	return 0;
}
/*
6 3
4 2 4 5 1 1
*/

例题2.防具布置

因为中间只有一个奇数,考虑求前缀和。则该奇数位以前的前缀和都是偶数,以后的都是奇数。二分这个分界点即可,注意判无解。

code
#include<bits/stdc++.h>
#define int long long

using namespace std;
const int N=2e5+5;
int T,n,s[N],e[N],d[N];
int check(int x)
{
	int sum=0;
	for(int i=1;i<=n;i++)
	{
		if(s[i]>x) continue;
		sum+=(min(e[i],x)-s[i])/d[i]+1;
	}
	return sum;
}
signed main()
{
	scanf("%lld",&T);
	while(T--)
	{
		scanf("%lld",&n);
		for(int i=1;i<=n;i++) scanf("%lld%lld%lld",&s[i],&e[i],&d[i]);
		long long l=1,r=(long long)(1ll<<31ll)-1ll;
		if((check(r)&1)==0) {cout<<"There's no weakness."<<endl;continue;}
		//cout<<l<<" "<<r<<endl;
		while(l<r)
		{
			int mid=(l+r)>>1;
			//cout<<mid<<" "<<check(mid)<<endl;
			if((check(mid)&1)==0) l=mid+1;
			else r=mid;
		}
		cout<<l<<" "<<check(l)-check(l-1)<<endl;
	}
	return 0;
}

例题3.最大均值

实数域上二分平均值。
check 时将区间求和转化为前缀和的形式,则对于每一个 \(i\),找到 \([1,i-l+1]\) 中最小的 \(j\) 并逐一判断能否满足条件。
\(j\) 的区间每次加 1,无需循环,开变量记录当前最小值即可。

code
#include<bits/stdc++.h>
using namespace std;
typedef double db;
const int N=1e5+5;
const db eps=1e-5;
int n,l,a[N],maxn;
db b[N];
bool check(db x)
{
	db minn=1e9;
	for(int i=1;i<=n;i++) b[i]=1.0*a[i]-x;
	//for(int i=1;i<=n;i++) cout<<b[i]<<" ";
	//cout<<endl;
	for(int i=1;i<=n;i++) b[i]=b[i-1]+b[i];
	for(int i=l;i<=n;i++)
	{
		minn=min(minn,b[i-l]);
		//cout<<i<<" "<<b[i]<<" "<<minn<<endl;
		if(b[i]-minn>=-eps) {return 1;}
	}
	return 0;
}
int main()
{
	scanf("%d%d",&n,&l);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),maxn=max(maxn,a[i]);
	db l=-1e9,r=maxn;
	while(r-l>eps)
	{
		db mid=(l+r)/2.0;
		if(check(mid)) l=mid;
		else r=mid;
	}
	printf("%.0lf\n",l*1000.0);
	return 0;
}

1.喂养宠物

二分养的兔子数量,求出对应每个兔子需要的食物数量。
将兔子按需要食物多少排序,从小往大买兔子,根据需要食物总和判断方案是否合法。

code
#include<bits/stdc++.h>
using namespace std;
const int N=55;
int n,t,h[N],g[N],c[N];
int minn=2e9;
int check(int x)
{
	for(int i=1;i<=n;i++) c[i]=h[i]+g[i]*(x-1);
	sort(c+1,c+n+1);
	int sum=0;
	for(int i=1;i<=x;i++) sum+=c[i];
	return sum;
}
int main()
{
	scanf("%d%d",&n,&t);
	for(int i=1;i<=n;i++) scanf("%d",&h[i]),minn=min(minn,h[i]);
	for(int i=1;i<=n;i++) scanf("%d",&g[i]);
	if(minn>t) {cout<<"0"<<endl;return 0;}
	int l=1,r=n;
	while(l<r)
	{
		int mid=(l+r+1)>>1;
		if(check(mid)<=t) l=mid;
		else r=mid-1;
	}
	cout<<l<<endl;
	return 0;
}

2.最小时间

两种情况:

  • 答案单调递减:判断 \(0\) 是否可行,因为数据保证有解,所以不可行就一定是第二种情况。
  • 答案单调递增:二分答案,从大到小排序取数。使用 nth_element 把复杂度降低一个 log。
code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+5;
int n,m,s,k[N],b[N],c[N];
bool check(int x)
{
	for(int i=1;i<=n;i++) c[i]=k[i]*x+b[i];
	nth_element(c+1,c+m,c+n+1,greater<int>());
	int sum=0;
	for(int i=1;i<=m;i++)
	{
		if(c[i]<0)continue;
		sum+=c[i];
		if(sum>=s) return 1;		
	}
	return 0;
}
signed main()
{
	scanf("%lld%lld%lld",&n,&m,&s);
	for(int i=1;i<=n;i++) scanf("%lld%lld",&k[i],&b[i]);
	int l=1,r=1e9;
	if(check(0)) {cout<<"0"<<endl;return 0;}
	while(l<r)
	{
		int mid=(l+r)>>1;
		if(check(mid)) r=mid;
		else l=mid+1;
	}
	cout<<l<<endl;
	return 0;
}

3.攻击法坛

留坑待填。

4.跳石头

二分最短跳跃距离,把所有距离小于 mid 的石头移走,统计移走石头数。

code
#include<bits/stdc++.h>
using namespace std;
int s,n,m,a[500005];
int check(int x)
{
	int now=0,ans=0;
	for(int i=1;i<=n+1;i++)
	{
		if(a[i]-a[now]<x) ans++;
		else now=i;
	}
	return ans;
}
int main()
{
	scanf("%d%d%d",&s,&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
	}
	a[n+1]=s;
	int l=1,r=s,mid;
	while(l<r)
	{
		mid=(l+r+1)>>1;
		if(check(mid)>m) r=mid-1;
		else l=mid;
	}
	cout<<r<<endl;
	return 0;
}
		

标签:二分,code,const,int,YbtOJ,sum,mid,算法,check
来源: https://www.cnblogs.com/ying-xue/p/16584995.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有