欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【POJ 2785】【折半枚举】4 Values whose Sum is 0【暑期 No.6】

程序员文章站 2024-03-20 18:11:46
...

题意:

        给定各有n个整数的四个数列A、B、C、D。要从每个数列中各取出1个数,使四个数的和为0。求出这样的组合的个数。当一个数列中有多个相同的数字时,把它们作为不同的数字看待。

 

分析:

        如果直接对四个数列进行枚举的话,将是O(n^4)的复杂度,因此可以考虑折半枚举的思想。

        将A、B数组相加的所有可能性列出来加入数组,O(n^2),再进行排序,O(n^2 logn),再对C、D数组相加的所有可能性进行枚举,O(n^2),再对枚举出的每一个值在第一个排序过的数组中进行二分搜索,O(logn)。大大降低了时间复杂度,这种思想需要学习。

 

代码:

#include <cstdio>
#include <iostream>
#include <algorithm> 
#define rep(i,a,b) for(int i = a;i <= b;i++)
using namespace std;
const int SIZE = 4010;

int a[5][SIZE];
int ans1[SIZE*SIZE],ans2[SIZE*SIZE];
int n,num1,num2;

int main()
{
	while(~scanf("%d",&n))
	{
		rep(i,1,n)
			scanf("%d%d%d%d",&a[1][i],&a[2][i],&a[3][i],&a[4][i]);
		num1 = 0;
		rep(i,1,n)
			rep(j,1,n)
				ans1[++num1] = a[1][i]+a[2][j];
		num2 = 0;
		rep(i,1,n)
			rep(j,1,n)
				ans2[++num2] = a[3][i]+a[4][j];
		int cnt = 0;
		sort(ans2+1,ans2+1+num2);
		rep(i,1,num1){
			int x = (-1)*ans1[i];
			cnt += upper_bound(ans2+1,ans2+1+num2,x)-lower_bound(ans2+1,ans2+1+num2,x);
			//巧妙运用lower_bound和upper_bound可以实现所有需要的二分形式
			//并且更加准确
			//需要充分掌握
			//因为如果数据中出现大量的相同元素,单纯的二分便不再适用,使用现有的函数更加高效 
		}
		printf("%d\n",cnt);
	}	
	return 0;
} 

相关标签: 折半枚举