第四十二题 UVA1152 和为0的4个值 4 Values whose Sum is 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).
题意翻译
给定四个整数集合A,B,C,D,每个集合有n个元素。从A,B,C,D四个结合中分别选出一个元素a,b,c,d,使得a+b+c+d=0。找到有多少组a,b,c,d满足上述条件。
输入格式
第一行一个正整数T,代表测试数据的组数。 对于任意一组数据,第一行一个正整数n,接下来n行一行四个整数,构成一个n×4的矩阵。矩阵中任意一行的第一、二、三、四列的整数分别代表集合A,B,C,D中的数字。
输出格式
T行,一行一个整数,代表T组测试数据的答案。
数据范围
n<=4000,集合中任意一个数绝对值小于等于2^28。
感谢@wang 提供翻译
输入输出样例
无
/*
这题算了一算 N^2LogN 时间复杂度上稍微有一点拮据
翻了翻以前的博客 搞OI时候学的各种玄学卡常数都给用上了
Get_L Get_R 两个函数可以用 C++的 upper_bound 和 lower_Bound 代替
代码上会更加简洁,但是我不会用,想看的自己百度一下 好像是很好用的俩昂个标准库函数
*/
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define Maxn 4002
using namespace std;
int A[Maxn],B[Maxn],C[Maxn],D[Maxn];
int S[Maxn * Maxn],cnt;
inline void Read(int &x) {
x = 0; register char c = getchar(); int f = 1; // register 寄存器
while(c > '9' || c < '0') { c = getchar(); f = -1; }
while(c >= '0' && c <= '9') { x = (x * 10 ) + c - '0'; c = getchar(); }
x *= f;
}
int main(int argc,char* argv[]) {
int n,T; scanf("%d",&T);
while(T--) {
scanf("%d",&n); cnt = 0;
for(int i=1; i<=n; i++) scanf("%d %d %d %d",&A[i],&B[i],&C[i],&D[i]);
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++) S[++cnt] = A[i] + B[j];
sort(S + 1, S + cnt + 1);
long long Ans = 0;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
Ans += upper_bound(S + 1,S + cnt + 1,-C[i]-D[j]) - lower_bound(S + 1,S + cnt + 1, -C[i]-D[j]) ;
printf("%lld\n",Ans);
if(T) printf("\n");
}
return 0;
}
lower_bound(起始地址,结束地址,要查找的数值) 返回的是数值 第一个 出现的位置。
upper_bound(起始地址,结束地址,要查找的数值) 返回的是数值 最后一个 出现的位置。
binary_search(起始地址,结束地址,要查找的数值) 返回的是是否存在这么一个数,是一个bool值。
1 函数lower_bound() 参考:有关lower_bound()函数的使用
功能:函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置.
注意:如果所有元素都小于val,则返回last的位置,且last的位置是越界的!!
2 函数upper_bound()
功能:函数upper_bound()返回的在前闭后开区间查找的关键字的上界,返回大于val的第一个元素位置
注意:返回查找元素的最后一个可安插位置,也就是“元素值>查找值”的第一个元素的位置。同样,如果val大于数组中全部元素,返回的是last。(注意:数组下标越界)
关于本题:
若S中有两个5 则说明A[i]+B[j] 有两种情况是5 Ans += upper_bound(S + 1,S + cnt + 1,-C[i]-D[j]) - lower_bound(S + 1,S + cnt + 1, -C[i]-D[j]) 用来统计
本来自己写的二分答案,后来发现我写的二分有错误,,,,,把二分改成了C++的标准库函数,我又发现我写的快速读入RE了,这还是把当年的二分代码,快读代码翻出来照着写的
唉 真不知道到底是怎么了,当年学的就不对,还是…
终于还是向upper_bound 和 lower_bound 低头了
二分答案出问题我认了,快速读入当年都这么写,也没啥毛病啊 怎么就还能RE呢,难道UVa和register过不去吗??(就这个RE是不是因为register的关系还是我在写上一句话的时候突然想起来的)
罢了罢了