1.利用lower_bound和upper_bound在多个数组中查找多个数组中某个元素
lower_bound(数组的初始位置,数组的末尾位置,要查找的数字):
从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标
upper_bound (数组的初始位置,数组的末尾位置,要查找的数字):
从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
binary_search (arr[],arr[]+size , indx)
判断某个元素是否出现(排好序,递增)
D-D:
for(int i=1; i<=n; i++) scanf("%d %d %d %d",&A[i],&B[i],&C[i],&D[i]);
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++) S[++cnt] = A[i] + B[j];
sort(S + 1, S + cnt + 1);
long long Ans = 0;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
Ans += upper_bound(S + 1,S + cnt + 1,-C[i]-D[j]) - lower_bound(S + 1,S + cnt + 1, -C[i]-D[j]) ;
printf("%lld\n",Ans);
2.二分的分类
(1)对一个区间中一个数的查找:能在一个折半的区间中找到index就结束,不行就根据index的大小更新区间,但前提一定是单调递增的区间
int WA(int[]nums,int index,int l,int r)
{
while(l<=r)//index是要查找的数
{
int mid=(l+r)/2;
if(a[mid]==index)
return mid;
else if(a[mid]>index)
r=mid-1;
else
l=mid+1;
}
}
(2)最值类(最大值最小/最小值最大)
while(l<=r)//放主函数中
{
int mid=(l+r)/2;
if(judge(mid))
{
res=mid;
l=mid+1;
}
else r=mid-1;
}
....
.....
......
cout<<res;
G-G:
给你你在N个月中每月的花费,你想将N个月分成M组,每组的月份是连续的,同一组的花费加起来,求所有分组中最高花费的最低值 先确定l和r的值,首先明确它要折半搜索的是一组花费的花费总和,r应该是N个月的总和花费,l应该是这N个月中最大的花费
judge函数:遍历各个月份,将花费不大于mid的月份归为一个组,统计在当前mid情况下能分成几组:如果组数小于M,这说明mid取大了,那就取半
#include<iostream>
#include<cstdio>
#include<cstring>
#define MMAX 100003
using namespace std;
int day[MMAX],N,M;
int judge(int mid)
{
int k=1;
int sum=0;
for(int i=0; i<N; i++)
{
if(sum+day[i]>mid)
{
sum=day[i];
k++;
continue;
}
sum+=day[i];
}
return k;
}
int main()
{
while(~scanf("%d%d",&N,&M))
{
int Max=0;
int sum=0;
for(int i=0; i<N; i++)
{
scanf("%d",&day[i]);
Max=max(Max,day[i]);
sum+=day[i];
}
int low=Max,high=sum,mid;
while(low<high)
{
mid=(low+high)/2;
if(judge(mid)<=M){
high=mid-1;
}
else low=mid+1;
}
cout<<low<<endl;
}
return 0;
}
H-H(最小的最大):石子过河
#include <iostream>
#include <algorithm>
using namespace std;
const int k=2e5+10;
int a[k];
long long l,n,m,i;
bool judge(long long mid)
{
long long start=0,res=0;
for( i=1; i<=n; i++)
{
if(a[i]-start<mid)
{
res++;
}
else
{
start=a[i];
}
}
if(res<=m) return 1;
else return 0;
}
int main()
{
cin>>l>>n>>m;
for(i=1; i<=n; i++)
{
cin>>a[i];
}
sort(a+1,a+1+n);
long long left,right,mid,re;
left=0;
right=l;
while(left<=right)
{
mid=(left+right)/2;
if(judge(mid))
{
left=mid+1;
}
else
{
right=mid-1;
}
}
cout<<right<<endl;
return 0;
}
结论:最大的最小,输出是left/low,带等于号放在right;
最小的最大,输出是right/high,带等于号放在left;