1. 程式人生 > >4 Values whose Sum is 0 POJ - 2785(二分查詢)

4 Values whose Sum is 0 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 .  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).


題目大意:從四列中分別選一個數,問使所選的數加和為0,有多少種選法。

思路:暴力的話複雜度是n^4,肯定超時,用二分(個人認為叫折半列舉更合適)簡化的話,複雜度有所降低。這裡說下折半列舉,就是分別列舉計算第1、2行 和第3、4行的加和分別是sum1[i]、sum2[i],再通過列舉sum1[i],sum2[i]計算結果。 然而這樣仍然超時,這裡在查詢sum1,sum2時,我們是逐個列舉的,太耗時。下面介紹一個簡化複雜度的技巧:利用二分查詢。先對sum1、sum2排序,逐個列舉sum1裡的數,在sum2中查詢 存在幾個sum2=(-sum1)。這裡用到upper_bound和lower_bound查詢。

 這裡:利用 函式 upper_bound 和lower_bound 的性質  upper_bound(sum1,sum1+n*n,-sum2[i])-lower_bound(sum1,sum1+n*n,-sum2[i])  表示在sum1中查詢值等於(-sum2)的個數。

下面上程式碼:

#include<stdio.h>
#include<iostream>
#include <map>
#include<set>
#include<algorithm>
#define inf 0x3f3f3f3f
using namespace std;
long long sum1[16100000],sum2[16100000],a[4100][4];
int main(){
    int n,i,j;
    long long sum=0;
    scanf("%d",&n);
    for(i=0;i<n;i++){
        scanf("%lld%lld%lld%lld",&a[i][0],&a[i][1],&a[i][2],&a[i][3]);
    }
    for(i=0;i<n;i++){
        for(j=0;j<n;j++){
            sum1[i*n+j]=a[i][0]+a[j][1];
            sum2[i*n+j]=a[i][2]+a[j][3];
        }
    }
    sort(sum1,sum1+n*n); //注意sum1、sum2的範圍是n*n
    sort(sum2, sum2+n*n);
    for(i=0;i<n*n;i++){
        sum+=upper_bound(sum1,sum1+n*n,-sum2[i])-lower_bound(sum1,sum1+n*n,-sum2[i]);
        //在sum1中查詢 值等於(-sum2) 的個數
    }
    printf("%lld\n",sum);
    return 0;
}