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

Posted Jiaxin-Li

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了刷题记录 && 算法杂谈折半枚举与upper_bound 和 lower_bound相关的知识,希望对你有一定的参考价值。

【什么是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;
}

  

以上是关于刷题记录 && 算法杂谈折半枚举与upper_bound 和 lower_bound的主要内容,如果未能解决你的问题,请参考以下文章

蓝桥杯3月刷题集训-A 枚举&模拟Day3

递归与分治思想:治思想 && 折半查找法(迭代 && 递归)

算法杂谈:关于算法的思考

数据结构与算法学习资料推荐&LeetCode刷题指北

刷题记录:[De1CTF 2019]Giftbox && Comment

np背包问题算法:折半枚举