Everyday English
Your optimal career is simply this: Share the real you with physical world through th e process of creative self-expression.
你的最佳职业很简单,就是这样:通过创造性自我表达的途径和世界分享真实的你。
前言
很多人对二分感到很苦恼,很困惑,可能是因为二分的边界很难掌握,也许是判断条件难写…
然而,很幸运,你找到了这篇文章,仔细看下去,这篇文章将带你学透二分!!!
二分模版
#include <iostream>
#include <vector>
using namespace std;
// 二分查找模板
int binarySearch(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
return mid;
} else if (nums[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1;
}
int main() {
// 示例用法
vector<int> nums = {1, 2, 3, 4, 5};
int target = 3;
int result = binarySearch(nums, target);
cout << "Target found at index: " << result << endl;
return 0;
}
记住,如果你不用万能头文件的话,一定要记得加#include <vector>
二分套这个模板,肯定没错!(只要判断条件写对)亲测有效!!!
下面的题目更能证明这句话!
洛谷小课堂B3627 立方根
题目描述
给定正整数n,求n sqrt 3。答案向下取整。
输入格式
仅一行,一个正整数 n。
输出格式
仅一行,一个正整数,表示 3 sqrt n。向下取整输出。
样例 #1
样例输入 #1
27
样例输出 #1
3
样例 #2
样例输入 #2
100000
样例输出 #2
46
样例 #3
样例输入 #3
1000000000000000
样例输出 #3
100000
思路点拨
1.求 的3次根(下取整),等价于找到 ,满足 。
2.这里 有单调性,故可以二分 。
3.找到最大符合条件的整数 即可。
4.二分上下界:l=0,r=10的5次方+1。
AC:
#include<bits/stdc++.h>
using namespace std;
long long x,l,r,mid;
int main(){
cin >> x;
l=0; r=100001;
while (r-l>1){
mid=(l+r)>>1;
if (mid*mid*mid<=x) l=mid; else r=mid;
}
cout << l << endl;
return 0;
}
分析:这题就是典型的二分查找入门题。
二分查找是什么
可能你听说过二分查找,二分查找和二分答案是不是一回事呢?答案是否定的。二分查找只是单纯的查找就可以了,简单的控制好边界条件。而二分答案也许稍复杂些。
二分查找也称折半查找,顾名思义,就是每次查找去掉不符合条件的一半区间,直到找到答案(整数二分)或者和答案十分接近(浮点二分)。
话不多说,到例题里去练练手。
洛谷小课堂P1102 A-B 数对
题目背景
出题是一件痛苦的事情!
相同的题目看多了也会有审美疲劳,于是我舍弃了大家所熟悉的 A+B Problem,改用 A-B 了哈哈!
题目描述
给出一串正整数数列以及一个正整数 C,要求计算出所有满足 A - B = C 的数对的个数(不同位置的数字一样的数对算不同的数对)。
输入格式
输入共两行。
第一行,两个正整数 N,C。
第二行,N 个正整数,作为要求处理的那串数。
输出格式
一行,表示该串正整数中包含的满足 A - B = C 的数对的个数。
样例 #1
样例输入 #1
4 1
1 1 2 3
样例输出 #1
3
思路点拨
这一题将A-B=C转换成A-C=B,首先将A数组每个元素出现的次数统计起来,用map映射,最后将A数组每次减一个C,再将A数组扫一遍,将所有映射的次数和加起来就是答案。
AC:
#include<bits/stdc++.h>
using namespace std;
using namespace std;
typedef long long LL;
LL a[200001];
map<LL,LL> m;
int main() {
int n;
LL c;
LL ans=0;
cin >> n >> c;
for(int i=1;i<=n;i++) {
cin >> a[i];
m[a[i]]++;
a[i]-=c;
}
for(int i=1;i<=n;i++) ans+=m[a[i]];
cout << ans << endl;
return 0;
}
最后,我们再来看一个浮点二分:
洛谷小课堂P1163 银行贷款
银行贷款
题目描述
当一个人从银行贷款后,在一段时间内他(她)将不得不每月偿还固定的分期付款。这个问题要求计算出贷款者向银行支付的利率。假设利率按月累计。
输入格式
三个用空格隔开的正整数。
第一个整数表示贷款的原值 w=0,第二个整数表示每月支付的分期付款金额 w,第三个整数表示分期付款还清贷款所需的总月数 m。
输出格式
一个实数,表示该贷款的月利率(用百分数表示),四舍五入精确到 0.1%。
数据保证答案不超过 300.0%。
样例 #1
样例输入 #1
1000 100 12
样例输出 #1
2.9
思路点拨
分析:对于月利率,大几率是小数,那么,我们就需要浮点二分。
月利率的范围可以放大些,比如,0~500,然后从这个范围里查,直到和答案极度相近,终止。 最后的l或r,精确位数之后就是正确✔答案啦!
AC:
#include<bits/stdc++.h>
using namespace std;
double n,m,k,l,r;
bool pd(double x){
return (pow(1.0/(1.0+x),k)>=1-n/m*x);
}
int main(){
cin>>n>>m>>k;
l=0;r=10;
while(r-l>=0.0001){
double mid=(l+r)/2;
if(pd(mid))r=mid;
else l=mid;
}
cout<<fixed<<setprecision(1)<<l*100;
return 0;
}
至此,相信你已经对二分查找有一个更加清晰的认识了。
课后再来几个练习题吧(洛谷里的):
1、眼红的Medusa
2、进击的奶牛
3、切绳子
以下题解是上面的题目的答案(一一对应)
1.AC:
#include<bits/stdc++.h>
using namespace std;
int n,m;
map<int,bool> v;
int a[101000];
int b[101000];
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=m;i++){
cin>>b[i];
v[b[i]]=true;
}
for(int i=1;i<=n;i++){
if(v[a[i]]){
cout<<a[i]<<" ";
}
}
return 0;
}
2.AC:
#include<bits/stdc++.h>
using namespace std;
int const N=1e5+5;
int a[N],n,m,l,r,mid;
bool C(int x){
int sum=1;
int last=1;
for(int i=2;i<=n;i++){
if(a[i]-a[last]>=x){
sum++;
last=i;
}
}
return sum>=m;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
sort(a+1,a+n+1);
l=0,r=1e9+5;
while(r-l>1){
mid=(l+r)/2;
if(C(mid)){
l=mid;
}
else{
r=mid;
}
}
cout<<l<<endl;
return 0;
}
3.AC:
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
double a[N],l,r,mid;
int n,k;
int C(double x){
int ans=0;
for(int i=1;i<=n;i++){
ans+=(int)(a[i]/x);
}
return ans>=k;
}
int main(){
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
}
l=0;r=1e9;
for(int t=0;t<100;t++){
mid=(r+l)*0.5;
if(C(mid)){
l=mid;
}
else{
r=mid;
}
}
printf("%.2lf",floor(l*100)/100);
return 0;
}
结尾
本篇文章共3890字,如果你能支持一下我,我十分感谢!!!
如果你喜欢或想了解一下其他的算法,可以看看以下这些:
前缀和与差分:
贪心:
排序:
函数:
C++第6讲max和min函数_c++ min函数-CSDN博客
for循环&数组:
if语句&else语句及运算:
C++第三讲:C++中的逻辑运算符及if else语句-CSDN博客
基础:
最后认识一下,我是爱编程的喷火龙廖,我们有缘再见!