1224
Description
现在给出A,B,C,D四个集合,每个集合中元素的个数n都是相同的,现在从每个集合中任取出一个数,记为a,b,c,d,现在要求统计有多少组不同的(a,b,c,d)使得a+b+c+d=0。
Input Format
第一行为各集合中元素的个数n;
第二行到第n+1行,每行有4个数字,依次为A,B,C,D中的一个元素。
Output Format
一行,为不同的(a,b,c,d)使得a+b+c+d=0的组数。
Sample Input
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
Limits
a,b,c,d的绝对值小于1000000,n小于500
//这是原题
咋一看似乎没有什么特别好的办法。一开始总是会想到暴力搜索。O(n^4)的复杂度似乎有点太坑了。
一开始也没有能够想到什么特别好的数据结构来实现。总是希望先把复杂度降下来再说。
然后灵光一现!
将式子变形为(a+b)=-(c+d),可以将A,B两集合中元素相加得到n^2个和的集合E,存储后,对C,D两集合中元素任意取和,查找和在E中出现的次数,累加即为解。
这是对原来的式子变形的结果。
然后我们如何来确定一共出现了多少次呢?
什么数据结构来实现比较好?
不追求速度的话,一般来说再用集合?
显然用集合不是最好的选择。
hashmap。
只不过会浪费大量的空间。但是速度足够快。
尽管我们也不知道测试数据里面是否对空间复杂度做出了多少限制。
但是总是值得一试的。
#include<cstdlib>
#include<cstdio>
#include<iostream>
using namespace std;
int s[4000003] = {0};//-2000000-2000003...0-4000003
int a[510];
int la;
int b[510];
int lb;
int c[510];
int lc;
int d[510];
int ld;
void init()
{
la = lb = lc = ld = 0;
}
int main()
{
ios::sync_with_stdio(false);
init();
int n,t1,t2,t3,t4;
int cou = 0;
cin >> n;
for (int i = 0; i < n;i++)
{
cin >> t1 >> t2 >> t3 >> t4;
a[la++] = t1;
b[lb++] = t2;
c[lc++] = t3;
d[ld++] = t4;
}
for (int i = 0; i < la; i++)
{
for (int j = 0; j < lb; j++)
{
s[(a[i] + b[j] + 2000000)] ++;
}
}
for (int i = 0; i < lc; i++)
for (int j = 0; j < ld; j++)
{
if (s[-((c[i] + d[j]) - 2000000)] != 0)cou+= s[-((c[i] + d[j]) - 2000000)];
}
cout << cou << endl;
//system("pause");
return 0;
}
事实证明,一开始的确没过。但并不是MLE,而是考虑不周全所致。
因为可能会有多组的和相等,所以在用hash的时候还是要注意一下。记录相加和相等组的数目。
嗯。最后加起来就得到了。