【刷题记录】 && 【算法杂谈】折半枚举与upper_bound 和 lower_bound

时间:2022-01-25 18:38:26

【什么是upper_bound 和 lower_bound】

简单来说lower_bound就是你给他一个非递减数列[first,last)和x,它给你返回非递减序列[first, last)中的第一个大于等于值x的位置。

而upper_bound就是你给他一个非递减数列[first,last)和x,它给你返回非递减序列[first, last)中的第一个大于值x的位置。

STL中实现这两种函数的算法就是二分。。。。。。

【upper_bound 和 lower_bound代码】

//STl中的lower_bound源代码
//这个算法中,first是最终要返回的位置
int lower_bound(int *array, int size, int key)
{
int first = 0, middle;
int half, len;
len = size; while(len > 0)
{
half = len >> 1;
middle = first + half;
if(array[middle] < key)
{
first = middle + 1;
len = len-half-1; //在右边子序列中查找
}
else
len = half; //在左边子序列(包含middle)中查找
}
return first;
}
//——————————upper_bound——————————————————
int upper_bound(int *array, int size, int key)
{
int first = 0, len = size-1;
int half, middle; while(len > 0){
half = len >> 1;
middle = first + half;
if(array[middle] > key) //中位数大于key,在包含last的左半边序列中查找。
len = half;
else{
first = middle + 1; //中位数小于等于key,在右半边序列中查找。
len = len - half - 1;
}
}
return first;
}
//______________End___________________________________________________________

【POJ 2785】

【题目原文】

The SUM problem can be formulated as follows: given four lists A, B, C, D of integer values, compute how many quadruplet (a, b, c, d ) ∈ A x B x C x D are such that a + b + c + d = 0 . In the following, we assume that all lists have the same size n .

【题目大意】

给定各有n个整数的4个数列A,B,C,D。要从每一个数列中各去出一个数,使四个数的和为0.求出这样组合的个数。(当同一数列中有相同数字时按不同数字看待——博主注)

【输入描述】

有n行,一行4个数,分别是A[i],B[i],C[i],D[i]

【输入样例】

6
-45 22 42 -16
-41 -27 56 30
-36 53 -37 77
-36 30 -75 -46
26 -38 -10 62
-32 -54 -6 45

【输出描述】

一个数

【输出样例】

5

【博主注释】

有5种情况,分别是-45-27+42+30    26+30-10-46    -32+22+56-46    -32+30-75+77    -32-54+56+36

【题目分析】

我们把这些数对半分成AB与CD考虑。先从AB中取出a[i],b[i]后,为了使总和为0则需要从CD中取出c[i]+d[i]=a[i]-d[i]。因此将这些情况枚举出来,再用upper_bound和lower_bound进行二分即可。时间复杂度为O(n^2 logn)

【代码】

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=4001;
int n;
int a[maxn],b[maxn],c[maxn],d[maxn];
int cd[16000001];
int lower_bound(int *array, int size, int key)
{
int first = 0, middle;
int half, len;
len = size;
while(len > 0)
{
half = len >> 1;
middle = first + half;
if(array[middle] < key)
{
first = middle + 1;
len = len-half-1; //在右边子序列中查 找
}
else
len = half; //在左边子序列(包含middle)中查找
}
return first;
}
int upper_bound(int *array, int size, int key)
{
int first = 0, len = size-1;
int half, middle;
while(len > 0)
{
half = len >> 1;
middle = first + half;
if(array[middle] > key) len = half; //中位数大于key,在包含last的左半边序列中查找.
else
{
first = middle + 1; //中位数小于等于key,在右半边序列中查找。
len = len - half - 1;
}
}
return first;
}
int main()
{
cin>>n;
for(int i=0;i<n;i++) cin>>a[i]>>b[i]>>c[i]>>d[i];
//for(int i=0;i<n;i++) cin>>b[i];
//for(int i=0;i<n;i++) cin>>c[i];
//for(int i=0;i<n;i++) cin>>d[i];
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++) cd[i*n+j]=c[i]+d[j];
}
sort(cd,cd+n*n);
long long res=0;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
int CD=-(a[i]+b[j]);
res+=upper_bound(cd,cd+n*n,CD)-lower_bound(cd,cd+n*n,CD);
}
}
cout<<res;
return 0;
}