a+b+c+d==0

利用排序和双指针解决四元组求和问题
该博客介绍了如何解决一个四元组求和问题,其中给定四个列表A、B、C和D,目标是找出所有使得a+b+c+d=0的四元组(a,b,c,d),其中a属于A,b属于B,c属于C,d属于D。博主提供了基于排序和双指针的方法,通过两次遍历数组并利用lower_bound和upper_bound函数来高效地计算满足条件的四元组数量。

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

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

数据范围 n<=2e

样例输入

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

样例输出

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

Sample Input

Copy to Clipboard
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

Copy to Clipboard
5

/*
 * @Description: To iterate is human, to recurse divine.
 * @Autor: Recursion
 * @Date: 2022-03-23 09:44:28
 * @LastEditTime: 2022-03-23 12:03:40
 */
#include<bits/stdc++.h>
using namespace std;
int T,n,sum;
int a[10000],b[10000],c[10000],d[10000];
int ab[200000001],cd[200000001];
// int a[10000][10000];

// void read()
// {
//     for(int i = 1;i <= n;i ++)
//         for(int j = 1;j <= 4;j ++)
//             cin >> a[i][j];
// }
// void dfs(int x)
// {
//     if(x == 4 + 1){
//         if(sum == 0)
//             ans++;
//         return;
//     }
//     for(int i = 1;i <= n;i ++){
//         sum += a[i][x];
//         dfs(x + 1);
//         sum -= a[i][x];
//     }

// }

// int main()
// {
//     cin >> T;
//     while(T--){
//         cin >> n;
//         read();
//         dfs(1);
//         cout << ans << endl;
//     }
// }

void read()
{
    for(int i = 0;i < n;i ++)
        cin >> a[i] >> b[i] >> c[i] >> d[i];
}

void solve()
{
    for(int i = 0;i < n;i ++)
        for(int j = 0;j < n;j ++){
            ab[i*n + j] = a[i] + b[j];
            cd[i*n + j] = c[i] + d[j];
        }
    sort(ab,ab + n*n);
    sort(cd,cd + n*n);
    long long int ans = 0;
    for(int i = 0;i < n*n;i ++){
        int temp = -ab[i];
        ans += upper_bound(cd,cd + n*n, temp) - lower_bound(cd,cd + n*n,temp);
    }
    /*
    upper_bound(first, last, val) 寻找在数组或容器的[first,last)范围第一个大于val的元素位置
    lower_bound(first, last, val)寻找在数组或容器的[first,last)范围第一个大于等于val的元素位置
    使用时必须为有序的数组或容器
    相减得到相等个数
    
    lower_bound:

    功能:查找非递减序列[first,last) 内第一个大于或等于某个元素的位置。

    返回值:如果找到返回找到元素的地址否则返回last的地址。(这样不注意的话会越界,小心)

    用法:int t=lower_bound(a+l,a+r,key)-a;(a是数组)。

    upper_bound:

    功能:查找非递减序列[first,last) 内第一个大于某个元素的位置。

    返回值:如果找到返回找到元素的地址否则返回last的地址。(同样这样不注意的话会越界,小心)
    
    用法:int t=upper_bound(a+l,a+r,key)-a;(a是数组)。
    */
    cout << ans << endl;
}

int main()
{
    int t;
    cin >> t;
    while(t--){
        cin >> n;
        read();
        solve();
    }
}

实现计算`a + b`结果的C语言代码有多种情况,以下是不同要求下的代码示例: ### 循环输入两个正整数`a`和`b`(`a, b ≤ 10000`),输出`a + b`的值,无输入时结束程序 ```c #include <stdio.h> int main(){ int a, b; while(scanf("%d %d", &a, &b) != EOF){ printf("%d\n", a + b); } return 0; } ``` 该代码通过`while`循环和`scanf`函数不断读取输入的两个整数,当没有输入时(即`scanf`返回`EOF`),循环结束,程序终止 [^1][^2]。 ### 每次运行只能输入一组数据,计算并输出`a + b`的值 ```c #include <stdio.h> int main() { int a, b; scanf("%d %d", &a, &b); int sum; sum = a + b; printf("第一种方法sum=%d", sum); return 0; } ``` 此代码使用`scanf`函数读取一组整数,计算它们的和并输出 [^3]。 ### 输入包含一个整数`T`表示测试实例的个数,后续有`2*T`行分别表示`A`和`B`两个正整数(整数长度不超过1000) ```c #include <stdio.h> #include <string.h> #define MAX_LEN 1001 // 大整数加法函数 void add(char *num1, char *num2, char *result) { int len1 = strlen(num1); int len2 = strlen(num2); int carry = 0; // 进位 int i = len1 - 1, j = len2 - 1, k = 0; while (i >= 0 || j >= 0 || carry) { int digit1 = (i >= 0) ? num1[i] - '0' : 0; int digit2 = (j >= 0) ? num2[j] - '0' : 0; int sum = digit1 + digit2 + carry; result[k++] = (sum % 10) + '0'; carry = sum / 10; i--; j--; } result[k] = '\0'; // 反转结果字符串 for (i = 0, j = k - 1; i < j; i++, j--) { char temp = result[i]; result[i] = result[j]; result[j] = temp; } } int main() { int T; scanf("%d", &T); for (int t = 0; t < T; t++) { char num1[MAX_LEN], num2[MAX_LEN], result[MAX_LEN]; scanf("%s %s", num1, num2); add(num1, num2, result); printf("%s\n", result); } return 0; } ``` 这段代码处理大整数加法,使用字符数组存储大整数,通过`add`函数实现大整数的加法运算,最后输出结果 [^4]。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值