UVA 1152 和为0的四个值 (二分+中途相遇)

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×B×C×D are such that a+b+c+d = 0. In the following, we assume that all lists have the same size n.
Input
The input begins with a single positive integer on a line by itself indicating the number of the cases following, each of them as described below. This line is followed by a blank line, and there is also a blank line between two consecutive inputs.
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 228) that belong respectively to A,B,C and D.
Output
For each test case, your program has to write the number quadruplets whose sum is zero. The outputs of two consecutive cases will be separated by a blank line.
Sample Input
1
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
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).

#include <algorithm>
#include <iostream>
#include<cmath>
#include<cstring>
#include<stdio.h>
#define maxn 4005
#define MAX 200000000
using namespace std;
/*
题目大意:给定四列数和其行数,让找出满足和为零的四元组的个数,
其中四元组满足每个数都在不同 的列数中。

对每两列进行两重循环枚举出所有和的情况并用整数栈记录,
然后排序,对另外两列枚举出的每个结果,在有序数组中进行二分查找,
总体复杂度为O(n^2logn),当然也要注意常数阶级,由于暂时不会哈希,
所以直接二分。

注意:对每个数的二分不是找这个数,而是找这个数的区间,
至于二分找区间问题,我们知道二分可以找左上界和右下界,但是混在一起用就不妥,
因为会有边界值的问题,这时借鉴他人之玉,,先搞出下界,
再循环暴力出所有个数(汗。。不知道会不会超时)

*/

long long  seq[4][maxn];
long long  tmp[MAX],cnt;

bool binary(long long x)
{
    int l=0,r=cnt-1;
    while(l<=r)
    {
        int mid=(l+r)/2;
        if(tmp[mid]>x)   r=mid-1;
        else if (tmp[mid]<x) l=mid+1;
        else {
            //cout<<x<<endl;
            return true;
        }
    }
    return false;
}

int main()
{
    int t;cin>>t;
    for(int tt=0;tt<t;tt++)
    {
        if(tt)
        puts("");
        int n;cin>>n;
        for(int j=0;j<n;j++)  cin>>seq[0][j]>>seq[1][j]>>seq[2][j]>>seq[3][j];

        cnt=0;
        long long ans=0;
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
               tmp[cnt++]=( seq[0][i]+seq[1][j] );

        sort(tmp,tmp+cnt);

        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
            {
                int l=0,r=cnt-1,mid;
                while(l<r)
                {
                    mid=(l+r)>>1;
                    if( tmp[mid] < -seq[2][i]-seq[3][j] )
                          l=mid+1;
                    else
                        r=mid;
                }
                while( l<cnt && tmp[l]==-seq[2][i]-seq[3][j] )
                {
                    ans++;l++;
                }
            }
            printf("%lld\n",ans);
        }
        return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值