uva 1152 二分查找+中途相遇法

题意:

       给定4个n元素集合,要求分别从中选取一个元素a,b,c,d使得a+b+c+d=0.问,有多少种说法?

题解:

       根据紫书算法,我们计算出a+b的所有和,放入vector数组中,同时计算c+d的所有和,放入vector数组中,之后暴力枚举a+b的所有和,在c+d和数组中二分查找-(a+b),这里需要注意的是原始的二分查找只会找到一个数据,数组中可能会有多个-(a+b),我们需要判断。PE了好几次,uva了格式很严格!

代码:

     

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long LL;
vector<LL> sumA,sumB;
int solve(int mid,LL ans)
{
    //cout<<mid<<ans<<endl;
    int count=0;
    int i=mid+1;
    int j=mid-1;
    while(sumB[i]==ans)
    {
        count++;
        i++;
    }
    while(sumB[j]==ans)
    {
        count++;
        j--;
    }
    return count;
}

int main()
{

    vector<LL> data[4];
    int T;
    cin>>T;
    LL num,tmp;
    while(T--)
    {
       cin>>num;
       for(int i=0;i<num;i++)
       {
            for(int j=0;j<4;j++)
            {
                cin>>tmp;
                data[j].push_back(tmp);
            }
       }
       LL sum1,sum2;
       for(int i=0;i<num;i++)
       {
           for(int j=0;j<num;j++)
           {
                sum1 = data[0][i]+data[1][j];
                sum2 = data[2][i]+data[3][j];
                sumA.push_back(sum1);
                sumB.push_back(sum2);
           }
       }
       LL sizA = sumA.size();
       LL sizB = sumB.size();
       int ans=0;
       sort(sumB.begin(),sumB.end());

       for(int i=0;i<sizA;i++)
       {
           LL se = -sumA[i];
           int right=sizB-1;
           int left =0;
           while(right>=left)
           {
              int mid = (right+left)>>1;
              if(sumB[mid]>se){
                 right=mid-1;
              }
              else if(sumB[mid]<se)
              {
                  left=mid+1;
              }
              else if(sumB[mid]==se){
                    //cout<<sumB[mid]<<se<<endl;
                ans++;
                int o=solve(mid,se);
                ans+=o;
                break;
              }
           }
       }
       cout<<ans<<endl;
       if(T!=0) cout<<endl;
       sumA.clear();
       sumB.clear();
       for(int j=0;j<4;j++)
       {
           data[j].clear();
       }
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值