例题8-3 和为0的4个值 UVa1152

1.题目描述:点击打开链接

2.解题思路:本题要求从4个集合中分别找4个数,使他们的和相加等于0的所有情况个数,由于每个元素的范围比较大,且一个集合的总量可以多达4000,直接写四重循环肯定TLE,需要优化,由a+b+c+d=0移项得a+b=-c-d,因此可以事先分别统计所有的a+b,-c-d的值到s,t数组中,排好序后在t数组中找s中的每一个元素,此时可以直接用upper_bound,lower_bound的差得到c,d的方案数,注意:由于s中可能有重复的元素,因此要记得加上第一次找到的c,d的方案数。总时间复杂度是O(n2*logn)

3.代码:

#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<set>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
using namespace std;

const int maxn = 4000 + 100;
int A[maxn], B[maxn], C[maxn], D[maxn];
int s[maxn*maxn], t[maxn*maxn];
int main()
{
	//freopen("test.txt", "r", stdin);
	int T;
	int n;
	scanf("%d", &T);
	while (T--)
	{
		memset(s, 0, sizeof(s));
		memset(t, 0, sizeof(t));
		scanf("%d", &n);
		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[(i - 1)*n + j] = A[i] + B[j];
			t[(i - 1)*n + j] = C[i] + D[j];
		}
		sort(s + 1, s + n*n + 1);
		sort(t + 1, t + n*n + 1);
		long long ans = 0;
		int k1, k2;
		s[0] = -999999999;
		for (int i = 1; i <= n*n; i++)
		{
			if (s[i] == s[i - 1])//如果有重复项,说明有其他的两个数也得到相同的和,此时要累加原来的解的个数
			{
				ans += (k2 - k1);
				continue;
			}
			k1 = lower_bound(t + 1, t + n*n + 1, (-s[i])) - t;//查找相反数的下界
			k2 = upper_bound(t + 1, t + n*n + 1, (-s[i])) - t;//查找相反数的上界
			ans += (k2 - k1);
		}
		printf("%lld\n", ans);
		if (T)printf("\n");
	}
	return 0;
}


你可能感兴趣的:(uva,贪心法)