【刷题记录】 && 【算法杂谈】折半枚举与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; }