二分类型题小结

(以下题目均来自洛谷LUOGU)

A.P2249 【深基13.例1】查找(入门)

#include<bits/stdc++.h>
#define FAST ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define ms(a,b) memset(a,b,sizeof(a))
#define MP make_pair 
#define rush() int T;cin>>T;while(T--)
#define ll long long
//可用 map 或者 stl-upper_bound 
using namespace std;
const int N = 1e7;
const int INF = 0x3f3f3f3f;
const double PI = acos(-1.0);
typedef pair<int,int> pii;

ll arr[N],num[N];
ll n,m,ans,p = 1;

int find(int x){
	int l = 1;
	int r = n;
		
	while(l < r){//二分答案 细节关键啊........... 
		int mid = (l + r) / 2;
		if(arr[mid] < ans)l = mid + 1;
		else r = mid;
	}
	
	if(arr[l] == ans)return l;
	return -1;
}

int main(){
	FAST;

	cin>>n>>m;
	
	for(int i = 1;i <= n;i++)cin>>arr[i];
	
	for(int i = 1;i <= m;i++){
		cin>>ans;
		num[i] = find(ans);
	}
	
	for(int i = 1;i < m;i++)cout<<num[i]<<" ";
	cout<<num[m];
	
	return 0;
}

B.P1024 一元三次方程求解(入门)

#include<iostream>
#include<cstdio>

using namespace std;

double a,b,c,d;
double f(double x){return (a * x * x * x + b * x * x + c * x + d);}

int main(){
	ios::sync_with_stdio(false);
	double cur1,cur2,mid;
	cin>>a>>b>>c>>d;
	
	double left = -100,right = -99,k = 0,l,r;
	while(k < 3 && right <= 101){
		
		l = left,r = right;
		cur1 = f(l),cur2 = f(r);
		
		if(f(l) == 0){
			printf("%.2lf ",l);//l是由 left继承过来的 写成f的格式 left一定要设置成ll 血的教训 求你了没有下次 
			k++;
		}
		else if(cur1 * cur2 < 0){
			k++;
			while(r - l >= 0.001){
				mid = (l + r) / 2.0;
				if(f(mid) * f(r) <= 0)l = mid;
				else r = mid;
			}
			printf("%.2lf ",l);
		}
		left++;
		right++;
	}	
	return 0;
} 

C.P1102 A-B 数对(入门)

#include<bits/stdc++.h>
#define FAST ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define ms(a,b) memset(a,b,sizeof(a))
#define MP make_pair 
#define rush() int T;cin>>T;while(T--)
#define ll long long
//不开ll见祖宗 
using namespace std;
const int N = 2e5 + 100;
const int INF = 0x3f3f3f3f;
const double PI = acos(-1.0);
typedef pair<int,int> pii;

ll arr[N],sum[N];
ll n,c;

int search(ll x){
	ll cnt = 1;
	for(int i = x - 1;i >= 1;i--){
		if(arr[i] == arr[x])cnt++;
		else break;
	}
	for(int i = x + 1;i <= n;i++){
		if(arr[i] == arr[x])cnt++;
		else break;
	}
	return cnt;
}

int main(){
	FAST;
	
	cin>>n>>c;
	
	for(int i = 1;i <= n;i++)cin>>arr[i]; 
	sort(arr + 1,arr + n + 1);
	
	for(int i = n;i > 1;i--){
		
		if(i <= n - 1 && arr[i] == arr[i + 1]){
			sum[i] = sum[i + 1];
			continue;
		}
		
		ll l = 1,r = i - 1;
		ll ans = arr[i] - c;
		while(l < r){
			int mid = (l + r) / 2;
			if(arr[mid] < ans)l = mid + 1;
			else if(arr[mid] > ans)r = mid - 1;
			else{
				l = mid;
				break;
			}
		}
		
		if(arr[l] == ans)sum[i] = search(l);
	}
	
	ll cur = 0;
	for(int i = 1;i <= n;i++)if(sum[i])cur += sum[i];
	
	cout<<cur;
	return 0;
} 

D.P1873 砍树(普及)

#include<bits/stdc++.h>
#define FAST ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define ms(a,b) memset(a,b,sizeof(a)) 
#define rush() int T;cin>>T;while(T--)
#define ll long long

using namespace std;
const int N = 10e6 + 1000;

ll n,m,term,ans[N],maxn = 0;

ll check(int mid){
	ll sum = 0;
	for(int i = 1;i <= n;i++){
		if(ans[i] - mid > 0)sum += ans[i] - mid;
	}
	return sum;
}

int main(){
	
	cin>>n>>m;
	for(int i = 1;i <= n;i++){
		cin>>ans[i];
		if(ans[i] > maxn)maxn = ans[i];
	}
	
	ll l = 1,r = maxn;
	while(l <= r){
		int mid = (l + r) / 2;
		if(check(mid) >= m)l = mid + 1;
		else r = mid - 1;
	}
	cout<<r<<endl;
	
	return 0;
} 

E.P2440 木材加工(普及)

#include<bits/stdc++.h>
#define FAST ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define ms(a,b) memset(a,b,sizeof(a))
#define MP make_pair 
#define rush() int T;cin>>T;while(T--)
#define ll long long
//二分答案的模板多样 细节最重要! 
using namespace std;
const int N = 1e5 + 100;
const int INF = 0x3f3f3f3f;
const double PI = acos(-1.0);
typedef pair<int,int> pii;

ll arr[N];
ll n,k,maxn,sum;

ll check(ll x){
	ll cnt = 0;
	for(int i = 1;i <= n;i++)cnt += arr[i] / x;
	return cnt;
}

int main(){
	FAST;
	
	cin>>n>>k;
	
	for(int i = 1;i <= n;i++){
		cin>>arr[i];
		maxn = max(maxn,arr[i]);
		sum += arr[i];
	}
	
	if(sum < k){cout<<"0";return 0;}
	if(sum < 2 * k){cout<<"1";return 0;}
	
	ll l = 1,r = maxn;
	while(l < r - 1){
		ll mid = (l + r) / 2;
		if(check(mid) >= k)l = mid;
		else r = mid;
	}

	cout<<l;
	return 0;
} 

F.P2678 跳石头(普及)

#include<bits/stdc++.h> 
using namespace std;
const int N = 5e4 + 100;
//一开始我的思路是这样的 先维护一个优先队列记录每一个跳跃距离 
//在check函数里面 我固定做 m 次 加法模拟移走岩石 查询队首元素是否大于mid
//但是我不会传递队列作为形参 导致我的check会永久改变原先队列

//题解的做法是保留原先的距离 在check里面计算跳跃距离 
int ans[N];
int l,n,m,maxn = 0;
//priority_queue<int, vector<int>, greater<int> >ans;

int check(int mid){
	int time = 0,term = 0;
	for(int i = 1;i <= n;i++){
		while(ans[i] - term < mid && i <= n)time++,i++;
		term = ans[i];
	}
	return time;
}

int main(){
	cin>>l>>n>>m;
	for(int i = 1;i <= n;i++)cin>>ans[i];
	//maxn = max(maxn,a[i]);

	ans[++n] = l;
	//maxn = max(maxn,l - a[n]);
	//ans.push(a[1]),ans.push(l - a[n]);
	//for(int i = 2;i <= n;i++)ans.push(a[i] - a[i - 1]);
	
	//sort(ans + 1,ans + n + 2);
	
	int low = 1,high = l;
	
	while(low <= high){
		int mid = (low + high) / 2;
		if(check(mid) <= m)low = mid + 1;
		else high = mid - 1;
	}
	
	cout<<high<<endl;
	return 0;
}

G.P1182 数列分段 Section II(普及)

#include<bits/stdc++.h>
#define FAST ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define ms(a,b) memset(a,b,sizeof(a))
#define MP make_pair 
#define rush() int T;cin>>T;while(T--)
#define ll long long
//二分答案的模板多样 细节最重要! 
using namespace std;
const int N = 1e7;
const int INF = 0x3f3f3f3f;
const double PI = acos(-1.0);
typedef pair<int,int> pii;

ll arr[N];
ll n,m,maxn;

ll check(ll x){
	
	ll sum = 0,cnt = 0;
	for(int i = 1;i <= n;i++){
		if(sum + arr[i] <= x)sum += arr[i];
		else sum = arr[i],cnt++;
	}
	return cnt;
}

int main(){
	FAST;
	ll sum = 0,maxn = -1;
	cin>>n>>m;
	
	for(int i = 1;i <= n;i++){
		cin>>arr[i];
		sum += arr[i];
		maxn = max(maxn,arr[i]);
	}
	
	ll l = maxn,r = sum;//这次错误在于端点问题 
	while(l <= r){
		ll mid = (l + r) / 2;
		if(check(mid) >= m)l = mid + 1;
		else r = mid - 1;
	}

	cout<<l;
	return 0;
} 

H.P3853 [TJOI2007]路标设置(普及+)

#include<bits/stdc++.h>
#define FAST ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define ms(a,b) memset(a,b,sizeof(a))
#define MP make_pair 
#define rush() int T;cin>>T;while(T--)
#define ll long long
using namespace std;
const int N = 1e5 + 100;
const int INF = 0x3f3f3f3f;
const double PI = acos(-1.0);
typedef pair<int,int> pii;
//几天的二分练习独立AC的题目寥寥无几.... 
//二分题注重细节: lr的选取, while边界确定,check函数准确性,数据范围......... 
int arr[N],len[N],cur[N];
int L,n,k;

int check(int x){
	int cnt = 0;
	
	for(int i = 2;i <= n;i++)
		if(arr[i] - arr[i - 1] >= x){
			cnt += (arr[i] - arr[i - 1]) / x;
			if((arr[i] - arr[i - 1]) % x == 0)cnt--;
		}
	
	if(cnt > k)return 0;
	return 1;
}

int main(){
	FAST;
	int sum = 0,maxn = -1;
	cin>>L>>n>>k;
	
	for(int i = 1;i <= n;i++){
		cin>>arr[i];
		if(i >= 2)len[i - 1] = arr[i] - arr[i - 1];
	}
	
	int l = 1,r = L;
	while(l < r){
		int mid = (l + r) / 2;
		if(!check(mid))l = mid + 1;
		else r = mid;
	}

	cout<<r;
	return 0;
} 
二分题都是细节怪物…
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值