C - 4 Values whose Sum is 0 POJ - 2785 (折半枚举)(二分搜索)

落花浮王杯 提交于 2020-04-06 19:47:08

训练赛上一题,当时没做出来,Orz太弱了

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

Hint

Sample Explanation: Indeed, the sum of the five following quadruplets is zero: (-45, -27, 42, 30), (26, 30, -10, -46), (-32, 22, 56, -46),(-32, 30, -75, 77), (-32, -54, 56, 30).
 
 
题意:给出4个数列,从每个数列中选取一个元素,有多少种组合使得和为0?
 

思路:首先如果直接for暴力O(n^4)肯定时不行的,然后我们能想到如果让  c[i]和d[i]合并  a[i]与b[i]合并 找他们的相反数有多少个就可以了,

 
 
 
 
   这里便出现了二分的应用:求 一个数 在一段序列中出现的次数。

   我们可以先用 lower_bound 查找第一个大于x的数

     函数lower_bound()在first和last中进行二分查找,如一个数组number序列1,2,2,4.lower_bound(2)后,返回的位置是1(下标)也就是2所在的位置,(只在单调递增的数组中适用)

     函数upper_bound()返回的在前闭后开区间查找的关键字的上界,如一个数组number序列1,2,2,4.upper_bound(2)后,返回的位置是3(下标)也就是4所在的位置,

代码:

#include <iostream>
#include <algorithm>
#include <string.h>
#include <cstdio>
#include <string>
#include <cmath>
#include <vector>
#include <stack>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
//#include <unordered_map>
#define Fbo friend bool operator < (node a, node b)
#define mem(a, b) memset(a, b, sizeof(a))
#define FOR(a, b, c) for(int a = b; a <= c; a++)
#define RFOR(a,b, c) for(int a = b; a >= c; a--)
#define sc(a) scanf("%d",&a)
#define off ios::sync_with_stdio(0)
bool check1(int a) { return (a & (a - 1)) == 0 ? true : false; }

using namespace std;
typedef pair<int, int> pii;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int Maxn = 5050;
const double pi = acos(-1.0);
const double eps = 1e-8;

int a[Maxn], b[Maxn], c[Maxn], d[Maxn];
int f[Maxn*Maxn], k=0;

int main() {
    int n;
    sc(n);
    FOR(i,1,n) {
        sc(a[i]), sc(b[i]), sc(c[i]), sc(d[i]);
    }
    FOR(i, 1, n) {
        FOR(j, 1, n) {
            f[k++] = c[i] + d[j];
        }
    }
    sort(f, f + k);
    ll ans = 0;
    FOR(i, 1, n) {
        FOR(j, 1, n) {
            ll t = -(a[i] + b[j]);
            //二分搜索取出cd中和为t的部分有多少个
            ans += upper_bound(f, f + n * n, t) - lower_bound(f, f + n * n, t);
        }
    }
    printf("%lld\n", ans);
}

 

 

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!