sjtu-acm-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
#include
#include
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的时候还是要注意一下。记录相加和相等组的数目。

嗯。最后加起来就得到了。


你可能感兴趣的:(SJTU,OJ,ACM)