POJ 2785 4 Values whose Sum is 0 枚举/二分查找

4 Values whose Sum is 0 [POJ 2785]

题目链接:http://poj.org/problem?id=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 228 ) 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 InputSample Output
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

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).

题意:给出n行数据,每行4列,现在每列中选择一个位置,使选择的四个位置上的数字和为0,问有多少种选择方法。(如果一列中有重复的数字,选择不同位置上的相同数字各算不同情况)
样例有六种选择方法: (-45, -27, 42, 30), (26, 30, -10, -46), (-32, 22, 56, -46),(-32, 30, -75, 77), (-32, -54, 56, 30).

思路:如果一列一列地枚举复杂度是O(n4),可以考虑先把第一列和第二列合并起来,合并的结果是第一列和第二列的数字两两相加,一共有n2项,因为n<=4000,所以可以存在数组里。然后对第三列和第四列也用同样的办法合并,逐一在第一列与第二列合并的数组中查找与他大小相等符号相反的数,把答案累加起来。

#include<iostream>
#include<algorithm>
using namespace std ;
#define ll long long
const ll N = 5000 ;
ll a[ N ] , b[ N ] , c[ N ] , d[ N ] , n ;
ll ab[ N*N ] , cd[ N*N ];
int main(){
    while( cin >> n ){
        ll ans = 0 ;
        for( int i = 1 ; i <= n ; i ++ ) cin >> a[ i ] >> b[ i ] >> c[ i ] >> d[ i ] ;
        //合并ab
        for( int i = 1 ; i <= n ; i ++ )
            for( int j = 1 ; j <= n ; j ++ )
                ab[ (i-1)*n + j ] = a[ i ] + b[ j ] ;
        //合并bc 
        for( int i = 1 ; i <= n ; i ++ )
            for( int j = 1 ; j <= n ; j ++ )
                cd[ (i-1)*n + j ] = c[ i ] + d[ j ] ;
                
        sort( ab+1 , ab+1+n*n ) ;
        for( int i = 1 ; i <= n*n ; i ++ ){
                ll pos1 , pos2 ;
                pos1 = lower_bound( ab+1 , ab+1+n*n , -cd[i] ) - ab ;
                pos2 = upper_bound( ab+1 , ab+1+n*n , -cd[i] ) - ab ;
                ll num ;
                //找-bc[i]在ab中出现的次数
                if( ab[pos1] == -cd[i] && ab[pos2-1] == -cd[i] ) num = pos2 - pos1 ;
                else num = 0 ;
                ans += num ;
        }
    cout <<  ans << "\n" ;
    }
return 0 ;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值