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

  

时间: 2024-12-25 21:07:19

【刷题记录】 && 【算法杂谈】折半枚举与upper_bound 和 lower_bound的相关文章

算法刷题记录

ACWING acwing 528. 奶酪 解题记录 acwing 471. 棋盘 解题记录 acwing 95 费解的开关 解题记录 dfs的几个基础示例 acwin 91~94 LEETCODE 刷题记录与资料 LEETCODE 1031. 两个非重叠子数组的最大和 dfs的几个基础示例 leetcode 刷题进展 leetcode 算法分类 原文地址:https://www.cnblogs.com/itdef/p/10854320.html

BZOJ 刷题记录 PART 4

[BZOJ1143]CTSC的题目...先用floyed传递闭包,然后直接上匈牙利算法. [BZOJ1452]从未写过的二维树状数组.好像很简单.. struct two_bit { int f[305][305]; inline void add(int x,int z,int A) { for (;x<=n;x+=L(x)) for (int y=z;y<=m;y+=L(y)) f[x][y]+=A; } inline int ask(int x,int z) { int ans=0; f

CSP-S集训刷题记录

$ CSP.S $ 集训刷题记录: $ By~wcwcwch $ 一.字符串专题: 1. [模板]$ manacher $ 算法 模型:求出字符串 $ S $ 中所有回文串的位置及长度. 个人理解:解决这类问题,回文串的对称性质最重要. 于复杂度最关键的一句话: $ f[i]=min~(~r-i~,~f[~mid\times2-i~]~)~ $ (实现不同,边界可能不一样) 这个 $ min $ 函数左边 $ r-i $ 是当前位置到它所属于的回文串边界的距离,右边 $ mid\times 2

[2015.6.28] OI刷题记录

FZSZOJ刷题记录: 1051 砝码称重: DP 多重背包 1058 liqeuer: 序列DP 1061 挖地雷:DP,注意需要倒过来做DP,同时记录路径. 1059 Number:DP 1054 数塔问题:同数字三角形,普通DP 1390 等式问题:爆搜,枚举每个+号或-号的位置 1006 中位数:维护大根堆+小根堆,每次插入调整 1005 Cube Stacking:并查集维护当前在第几个和当前集合的高度,并查集变种. 1073 DNA分子的最佳比对:序列DP 1110 奖学金:傻逼题,

BZOJ 刷题记录 PART 5

拖了好久才写的. [BZOJ2821]接触分块大法.这道题略有点新颖.首先我们先分块,然后统计每块中每个数出现的个数. 下面是联立各个方块,预处理出第I个方块到第J个方块出现正偶数次数的个数. for (i=1;i<=s;i++) { for (j=i;j<=s;j++) { sum[i][j]=sum[i][j-1]; for (k=a[j].l;k<=a[j].r;k++) { temp[data[k]]++; if (!(temp[data[k]]&1)) sum[i][j

leetcode刷题记录(2)

301. Remove Invalid Parentheses Remove the minimum number of invalid parentheses in order to make the input string valid. Return all possible results. Note: The input string may contain letters other than the parentheses ( and ). Examples: "()())()&q

BZOJ 刷题记录 PART 2

[前言]最近感觉状态不错.做题几乎不看题解了.(一群大牛(FZ&WCY)在旁边喷:你刷水题有意思!)但是至少这也是一种进步吧.特别是权限题中有很多思维题. [BZOJ1055]就是一个简单的区间DP.重要代码: for (l=2;l<=L;l++) for (i=1;i<=L-l+1;i++) { j=i+l-1; for (k=0;k<4;k++) for (cut=i;cut<j;cut++) for (p=0;p<4;p++) if (f[i][cut][p])

BZOJ 刷题记录 PART 3

[前言]还是强调要少看题解. [BZOJ1090]简单的区间DP.值得注意的是:在压缩的时候,如果是10个A压缩,那么化成(10)A后有5个字符而不是4个!(我在这里被坑了好长时间!)以下是核心代码: for (len=2;len<=L;len++) for (i=1;i<=L-len+1;i++) { j=i+len-1; for (k=i;k<j;k++) f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]); for (l=1;l<=len/2;l++

暑期刷题记录

已经决定不玩空间了,在这里开一贴,用来记录暑假期间刷过的每一题. 时间从7.29号开始计算. 1. HDU 4883 TIANKENG’s restaurant    ( 贪心 ) 这个是bestcoder #2 的第一题,,居然想半天没有做出来,简直是太弱了,居然又在分情况讨论 题目大意:TIANKENG的饭店有客人陆续到达,如果再一批客人没有走的情况下,新来的客人就需要另外的座位,问最少需要多少座位. 题解: 贪心算法,首先对所有时间进行排序(时间相同以人数为第二关键字), 然后如果是到达,