POJ2785 (二分)

题面:

Description:
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 .
Input
The first line of the input file contains the size of the lists n (this value can be as large as 4000). We then have n lines containing four integer values (with absolute value as large as 2 28 ) that belong respectively to A, B, C and D .
Output
For each input file, your program has to write the number quadruplets whose sum is zero.
Sample Input
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
Sample Output
5

题意

给出4个长度为n的四个数组A, B, C,D,让你求出所有从A, B, C, D中各取一个数,使得这4个数相加等于0的方案总数

解法

第一次尝试暴力膜,TLE

二分

思路:

用两个n * n的数组sum1, sum2分别存下A和B的所有元素之和还有C和D的所有元素之和,然后枚举sum1里的每个元素,在sum2里二分查找他的负值,如果找到,则说明他们的和为0。

脑子遇到的坑!

惯性思维里二分查找只是判断x在数组a里有没有,但是这道题不能这样做,因为有可能出现不同的C[i] + D[i]组合但是他们的和相同,存在sum2里,这样子如果只判断-sum1[i]是否存在于sum2里的话是不够的,因为sum2里可能有多个-sum1[i],也就是有多种可能,如果单纯判断有没有的话就会漏掉一些情况。所以二分查找完了还需要计数,返回值是sum2里有多少个sum1[i]

代码

#include <stdio.h>
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <string>
#include <cstring>
#include <algorithm>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <ctime>
#include <vector>
#include <list>
#include <iomanip>
#include <numeric>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define ms(s) memset(s, 0, sizeof(s))
#define rep(i, n) for (int i=0; i<(n); i++)
#define Rep(i, n) for (int i=1; i<=(n); i++)
#define range(x) (x).begin(), (x).end()
#define read(x) freopen(x, "r", stdin);
const int inf = 0x3f3f3f3f;
#define maxn 4005
#define LOCAL
long long int a[maxn][4];
long long int b[maxn * maxn];
long long int c[maxn * maxn];
long long int n, t = 0;
//优化之后的二分查找
int binary_search(int a){
    int r = t - 1;
    int l = 0;
    while (r - l >= 1){
        int m = (r + l) / 2;
        if (c[m] == a){
            int ans = 0;
            //主要是这里,这里返回的是从l到r出现x的次数,而不是单纯的true
            for (int i = l; i <= r; i++){
                if (c[i] == a) ans++;
            }
            return ans;
        }
        else if (a > c[m]){
            l = m + 1;
        }
        else{
            r = m; 
        }
    }
    return 0;
}
//打印调试函数
void print(){
    printf("t = %d\n", t);
    for (int i = 0; i < t; i++){
        printf("%lld %lld\n", b[i], c[i]);
    }
}
int main(int argc, char * argv[]) {
//  freopen("in.txt", "r", stdin);
    while (cin >> n){
        int temp;
        long long int ans = 0;
        t = 0;
        for (int i = 0; i < n; i++){
            //用a[i][0 ~ 3]代替了ABCD
            cin >> a[i][0] >> a[i][1] >> a[i][2] >> a[i][3];
        }

        for (int i = 0; i < n; i++){
            for (int j = 0; j < n; j++){
                //把每个和存进b和c里
                b[t] = a[i][0] + a[j][1];
                c[t++] = a[i][2] + a[j][3];
            }
        }
        sort(c, c + t);
        for (int i = 0; i < t; i++){
            if (temp = binary_search(-b[i])){
                //累加返回c里的-b[i]的个数
                ans += temp;
            }
        }
        cout << ans << endl;
    }
    return 0;
}
    原文作者:Andywu_0010
    原文地址: https://www.jianshu.com/p/300af7e6d4a3
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞