LevOJ P1748 a+b+c+d=0

题目描述

求和问题可以被看做是以下的公式,给定 A,B,C,D 四个列表,计算有多少四元组满足 (a, b, c, d) ∈ A × B × C × D 且 a + b + c + d = 0。我们推测所有的列表都有 n 个数字。

注:不同的四元组是指元素位置不一样的四元组

数据范围 n<=2e3

样例输入

输入的第一个数字指明有 T 组。每一组这样描述,第一行是列表大小 n, 然后有 n 行。每一行都有四个整型数字,分别属于 A,B,C,D 四列。

样例输出

对于每一个测试用例,统计有多少个四元组满足他们的和是 0 。每一组数据一行。

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

基本思路

本题求的是四元组求和为零,我们可以先从简单的二元组开始考虑,对于二元组求和为零的问题,我们可以遍历其中一个元组的每个元素,并且在另一个元组中查找是否存在这个元素的相反数,如果存在,那么就有一组符合条件,查找的过程我们就可以采用二分搜索。依此类推,对于三元组,我们可以先把其中两个元组的各个元素可能的和都求出来,放入一个新的元组中,然后转换为二元组求和为零的问题,那么四元组的话,先两两求和,然后转换为二元组问题

AC代码

#include<iostream>
#include<algorithm>
using namespace std;
int sum[400010];
int ans;
//二分查找
void binary_search(int x,int length)
{
    int left = 1, right = length-1;
    while (left <= right)
    {
        int mid = (left + right) / 2;
        //如果查找到这个值的话,我们不能急着直接令ans++
        //因为这个元组中不一定只有一个元素等于x
        //我们应该判断mid前面与mid后面是否也等于x,因此还要向前与向后搜索
        if (sum[mid] == x)
        {
            ans++;
            int i=mid,j=mid;
            //向前搜索
            while (sum[i - 1] == x)
            {
                ans++;
                i--;
            }
            //向后搜索
            while (sum[j + 1] == x)
            {
                ans++;
                j++;
            }
            return;
        }
        else if (sum[mid] > x)       right = mid - 1;
        else                                      left = mid + 1;
    }
    return;
}
int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        int n;
        cin >> n;
        //存储四元组
        int arr[2010][10];
        int i, j;
        for (i = 1; i <= n; i++)
        {
            for (j = 1; j <= 4; j++)
            {
                cin >> arr[i][j];
            }
        }
        //计算前面两个元组中所有元素可能的和
        int k=1;
        for (i = 1; i <= n; i++)
        {
            for (j = 1; j <= n; j++)
            {
                sum[k] = arr[i][1] + arr[j][2];
                k++;
            }
        }
        //注意:进行二分搜索的前提是有序的
        //因为我是从sum[1]开始存储的,所以是sort(sum+1,sum+k)
        //如果从sum[0]开始存储的话,这里应该是sort(sum,sum+k-1)
        sort(sum + 1, sum + k);
        int length = k;
        //计算后两个元组中所有元素可能的和
        //这里可以一边计算,一边进行二分搜索
        for (i = 1; i <= n; i++)
        {
            for (j = 1; j <= n; j++)
            {
                int sum = arr[i][3] + arr[j][4];
                //注意,查找的是给定值的相反数,所以要加个-号
                binary_search(-sum, length);
            }
        }
        cout << ans << endl;
        //注意ans要重置,因为定义的是全局变量
        ans = 0;
    }
    return 0;
}

在这里插入图片描述
时间也挺长的,如果有更加优秀的方法,欢迎指出!

  • 17
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ttzif

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值