二分相关的练习

排序练习

大统领投票

题目描述
​ 第一届地球大统领开始选拔,全地球的所有生物都积极参与投票,现在已知得票结果,请输出新当选的得票数最多的地球大统领的编号和得票数。

输入
​ 输入第一行为一个整数 NN 表示参选生物数。(1≤N≤100)(1≤N≤100)
​ 接下来 NN 行,每行一个整数,表示第 ii 名参选生物的票数。票数不会超过 10001000位。
输出
​ 输出得票数最多的生物的编号和票数。

样例输入
3
123456799
123456789132456789123456789
11111111111111
样例输出
2
123456789132456789123456789

#include <iostream>
#include<string>
#include<algorithm> 
using namespace std;
//符串读入可以直接比较大小
struct node{
	int num;
	string s;
};
int n;
node p[105];//本质是个类,这里是结构体数组 
bool cmp(node a,node b){//sort就是从小到大排序,自定义可以加入cmp,返回类型为bool。
	if(a.s.size()==b.s.size()){
		return a.s>b.s;
	}
	return a.s.size()>b.s.size()
}
int main() {
 	cin>>n;
 	for(int i=1;i<=n;i++){
 		cin>>p[i].s;
 		p[i].num=i;
	 }
	 sort(p+1,p+n+1,cmp);
	 cout<<p[1].num<<endl<<p[1].s<<endl;
	return 0;
}

二谁拿了最多讲学金

题目描述
某校的惯例是在每学期的期末考试之后发放奖学金。发放的奖学金共有五种,获取的条件各自不同:
1.院士奖学金,每人 80008000 元,期末平均成绩高于 8080 分(>80>80),并且在本学期内发表 11 篇或 11 篇以上论文的学生均可获得;
2.五四奖学金,每人 40004000 元,期末平均成绩高于 8585 分(>85>85),并且班级评议成绩高于 8080 分(>80>80)的学生均可获得;
3.成绩优秀奖,每人 20002000 元,期末平均成绩高于 9090 分(>90>90)的学生均可获得;
4.西部奖学金,每人 10001000 元,期末平均成绩高于 8585 分(>85>85)的西部省份学生均可获得;
5.班级贡献奖,每人 850850 元,班级评议成绩高于 8080 分(>80>80)的学生干部均可获得;
只要符合条件就可以得奖,每项奖学金的获奖人数没有限制,每名学生也可以同时获得多项奖学金。例如姚林的期末平均成绩是 8787 分,班级评议成绩 8282 分,同时他还是一位学生干部,那么他可以同时获得五四奖学金和班级贡献奖,奖金总数是 48504850元。
现在给出若干学生的相关数据,请计算哪些同学获得的奖金总数最高(假设总有同学能满足获得奖学金的条件)。

输入
第一行是 11 个整数 N(1≤N≤100)N(1≤N≤100),表示学生的总数。
接下来的 NN 行每行是一位学生的数据,从左向右依次是姓名,期末平均成绩,班级评议成绩,是否是学生干部,是否是西部省份学生,以及发表的论文数。
姓名是由大小写英文字母组成的长度不超过 2020 的字符串(不含空格);
期末平均成绩和班级评议成绩都是 00 到 100100 之间的整数(包括 00 和 100100);
是否是学生干部和是否是西部省份学生分别用 11 个字符表示,YY 表示是,NN 表示不是;
发表的论文数是 00 到 1010 的整数(包括 00 和 1010)。
每两个相邻数据项之间用一个空格分隔。
输出
包括 33 行。
第 11 行是获得最多奖金的学生的姓名。
第 22 行是这名学生获得的奖金总数。如果有两位或两位以上的学生获得的奖金最多,输出他们之中在输入文件中出现最早的学生的姓名。
第 33 行是这 NN 个学生获得的奖学金的总数。

样例输入
4
YaoLin 87 82 Y N 0
ChenRuiyi 88 78 N Y 1
LiXin 92 88 N N 0
ZhangQin 83 87 Y N 1
样例输出
ChenRuiyi
9000
28700

#include <iostream>
#include<string>
#include<algorithm> 
using namespace std;

struct person{
	string name;
	int avg,cla,paper,m,num;
	char off,west;
};
int n,ans;
person stu[105];
bool cmp(person a,person b){
	if(a.m==b.m){
		return a.m>b.m;
	}
	return a.m>b.m;
}
int func(int i){
	int t=0;
	if(stu[i].avg>80&&stu[i].paper>=1)t+=8000;
	if(stu[i].avg>85&&stu[i].cla>80)t+=4000;
	if(stu[i].avg>90)t+=2000;
	if(stu[i].avg>85&&stu[i].west=='Y')t+=1000;
	if(stu[i].cla>80&&stu[i].off=='Y')t+=850
	return t;
}
int main() {
  	cin>>n;
  	for(int i=0;i<n;i++){
  		cin>>stu[i].name>>stu[i].avg>>stu[i].cla<<stu[i].off<<stu[i].paper;
  		stu[i].num=i;
  		stu[i].m=func(i);
  		ans+=stu[i].m;
	  }
	  sort(stu,stu+n,cmp);
	  cout<<stu[0].name<<endl<<stu[0].m<<endl<<ans<<endl;
	return 0;
}

二分法

吃瓜群众

题目描述
​ 某地总共有 MM 堆瓜,第 ii 堆瓜的数量为 XiXi。现有 NN 组群众现在想要吃瓜,第 ii 组群众想要吃的瓜的数量为 YiYi。现在对于每组想吃瓜的群众,需要在 MM 堆瓜中查找对应数量的一堆瓜,并输出那堆瓜的编号,若找不到对应数量的一堆,则输出 00。

输入
​ 输入共 33 行。
​ 第一行两个整数 M,NM,N。
​ 第二行 MM 个整数分别表示 X1,X2…XMX1,X2…XM。(保证各不相同)
​ 第三行 NN 个整数分别表示 Y1,Y2…YNY1,Y2…YN。(保证各不相同)
输出
​ 对于每个 YiYi 输出一行一个整数为对应数量的瓜的编号,若没有对应数量的瓜,则输出 00。

样例输入
5 3
1 3 26 7 15
26 99 3
样例输出
3
0
2

#include <iostream>
#include<algorithm> 
using namespace std;

struct node{
	int cnt,num;
};
int n,ans;
node wm[100005];
bool cmp(const node &a,const node &b){
	return a.num<b.num;
}

int main() {
  	cin>>n>>m;
  	for(int i=0;i<n;i++){
  		cin>>wm[i].num;
  		wm[i].cnt=i+1;
	  }
	  sort(wm,wm+n,cmp);
	  for(int i=0;i<m;i++){
	  	int t,f=0,l=0,r=n-1;
	  	cin>>t;
	  	while(l<=r){
	  		int mid=(l+r)/2;
	  		if(t==wm[mid].num){
	  			f=wm[mid].cnt;
	  			break;
			  }
			if(t<wm[mid].num){
				r=mid-1;
			}else{
				l=mid+1
			}
		  }
		  cout<<f<<endl;
	  }
	return 0;
}

吃瓜升级

题目描述
​ 某地总共有 MM 堆瓜,第 ii 堆瓜的数量为 XiXi。现有 NN 组群众现在想要吃瓜,第 ii 组群众想要吃的瓜的数量为 YiYi。现在对于每组想吃瓜的群众,需要在 MM 堆瓜中查找大于等于需要数量的第一堆瓜,并输出那堆瓜的编号,若所有瓜堆的数量均小于需要数量,则输出 00。

输入
​ 输入共 33 行。
​ 第一行两个整数 M,NM,N。
​ 第二行 MM 个整数分别表示 X1,X2…XMX1,X2…XM。(保证各不相同)
​ 第三行 NN 个整数分别表示 Y1,Y2…YNY1,Y2…YN。(保证各不相同)
输出
​ 对于每个 YiYi 输出一行一个整数为大于等于需要数量的第一堆瓜的编号,若所有瓜堆的数量均小于需要数量,则输出 00。

样例输入
5 5
1 3 26 7 15
27 10 3 4 2
样例输出
0
5
2
4
2

#include <iostream>
#include<string>
#include<algorithm> 
using namespace std;
//这题是上一题的升级,本题要注意mid是否在区间 。可以把数组按照是否符合要求改为01的数组 
struct node{
	int cnt,num;
};
int n,m;
node wm[100005];
bool cmp(const node &a,const node &b){
	return a.num<b.num;
}
int main() {m 
  	cin>>n>>m;
  	for(int i=0;i<n;i++){
  		cin>>wm[i].num;
  		wm[i].cnt=i+1;
	  }
	  wm[n].cnt=0;
	  wm[n].num=2100000000;
	  sort(wm,wm+n+1,cmp);
	  for(int i=0;i<m;i++){
	  	int t,l=0,r=n-1;
	  	cin>>t;
	  	while(l!=r){           //左右两边都来 
	  		int mid=(l+r)/2;
	  		if(t<=wm[mid].num){
	  			r=mid;
			  }else{
				l=mid+1
			}
		  }
		  cout<<wm[l].cnt<<endl;
	  }
	return 0;
}

后面再慢慢更新吧,打算把自己的学习路线啥的也整理一下不然感觉学的老是忘啊。


更新线的拉,慢慢整不着急。最近有点小忙。下次看看能不能搞定思维导图啥的,毕竟算法题还是有点是外带的感觉。

原木切割

题目描述
​ 某林业局现在 NN 根原木,长度分别为 XiXi,为了便于运输,需要将他们切割成长度相等的 MM 根小段原木(只能切割成整数长度,可以有剩余),小段原木的长度越大越好,现求小段原木的最大长度。例如,有 33 根原木长度分别为 6,15,226,15,22,现在需要切成 88 段,那么最大长度为 55。

输入
​ 第一行两个整数 N,MN,M。(1≤N≤100,000,1≤M≤100,000,000)(1≤N≤100,000,1≤M≤100,000,000)
​ 接下来 NN 行,每行一个数,表示原木的长度 XiXi。(1≤Xi≤100,000,0001≤Xi≤100,000,000)
输出
​ 输出小段原木的最大长度, 保证可以切出 MM 段。

样例输入
3 8
6
15
22
样例输出
5

#include<iostream>
using namespace std;
//二分答案,需要按照题目具体考虑
int n,m,num[100005],lr;
int func(int len){
	int s=0;
	for(int i=0;i<n;i++){
		s+=num[i]/len;	
	}
	return s;
}
int main(){
	cin>>n>>m;
	for(int i=0;i<n;i++){
		cin>>num[i];
		lr=max(lr,num[i]);
	}
	int l=1,r=lr;
	while(l!=r){
		int mid=(l+r+1)/2;
		int s=func(mid);
		if(s>=m){
			l=mid;
		}else{
			r=mid-1;
		}
	}
	cout<<l<<endl;
	return 0;
}

切绳子

题目描述
​ 有 NN 条绳子,它们的长度分别为 LiLi。如果从它们中切割出 KK 条长度相同的绳子,这 KK 条绳子每条最长能有多长?答案保留到小数点后 22 位(直接舍掉 22 位后的小数)。

输入
​ 第一行两个整数 NN 和 KK,接下来 NN 行,描述了每条绳子的长度 LiLi。
输出
​ 切割后每条绳子的最大长度,保证答案大于零。

样例输入
4 11
8.02
7.43
4.57
5.39
样例输出
2.00

#include<iostream>
#include<cstdio>
using namespace std;
int n,m;
double num[10005],tr;
int func(double len){
	int s=0;
	for(int i=0;i<n;i++){
		s+=num[i]/len;
	}
	return s;
}


int main(){
	cin>>n>>m;
	for(int i=0;i<n;i++){
		cin>>num[i];
		tr=max(tr,num[i]);
	}
	double l=0,r=tr;
	while(r-l>0.00001){ //和精度相关,比较友好的一道题
		double mid =(l+r)/2;
		int s=func(mid);
		if(s>=m){
			l=mid;
		}else{
			r=mid;
		}
	}
	//直接用会四舍五入了改用点数学的
	 printf("%.2f\n",(int)(l*100)/100.0);

	return 0;
}

分座位

题目描述
​ 某公司的程序猿每天都很暴躁,因为他们每个人都认为其他程序猿和自己风格不同,无法一同工作,当他们的工位的编号距离太近时,他们可能会发生语言甚至肢体冲突,为了尽量避免这种情况发生,现在公司打算重新安排工位,因为有些关系户的工位是固定的,现在只有一部分工位空了出来,现在有 NN 个程序猿需要分配在 MM 个工位中,第 ii 个工位的编号为 XiXi,工位编号各不相同,现在要求距离最近的两个程序猿之间的距离最大,求这个最大距离是多少。XiXi 和 XjXj 工位之间距离为|Xi−Xj||Xi−Xj|。

输入
​ 输入共 M+1M+1 行。
​ 第一行两个整数 M,NM,N。(1≤N≤M≤100,000)(1≤N≤M≤100,000)
​ 接下来 MM 行,每行一个数,表示剩余的工位的编号。
输出
​ 输出距离最近的两个程序猿之间的最大距离。

样例输入
5 3
1
2
8
4
9
样例输出
3

#include<iostream>
#include<algorithm>
using namespace std;
int n,m,num[100005],tr;
int func(int d){
	int s=1,last=num[0];
	for(int i=1;i<n;i++){
		if(num[i]-last>=d){
			s++;
			last=num[i];
		}	
	}
	return s;
}


int main(){
	cin>>n>>m;
	for(int i=0;i<n;i++){
		cin>>num[i];
		tr=max(tr,num[i]);
	}
	sort(num,num+n);//小到大 
	int l=1,r=tr;
	while(l!=r){
		int mid =(l+r+1)/2;
		int s=func(mid);
		if(s>=m){
			l=mid;
		}else{
			r=mid-1;
		}
	}
	cout<<l<<endl;
	return 0;
}

总结

这几道题都差不了太多,二分查找大概也都差不多。1.普通的二分查找,就课本上那种。
2.二分查找的特殊情况就是按照题目分000011111或者可以111110000的特殊情况。

//000011111
while(l!=r){
mid=(l+r)/2;
l=mid+1;
r=mid;
}
//111110000
while(l!=r){
mid=(l+r+1)/2;
l=mid;
r=mid-1;
}

3.二分答案:就是先给出了二分的答案,一般是和那两种特殊情况差不多,不过会按照题目的不同来找不同的1的位置

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值