题目链接:POJ 2785 4 Values whose Sum is 0(中途相遇法)
-
中途相遇法,还有一个名字感觉更加妥帖一点,叫:折半枚举。 有时候,当问题的规模较大时,无法枚举所有元素的组合,但能够枚举一半的元素组合,此时,将问题拆成两半后分别枚举,再合并他们的结果这一方法往往非常有效。
-
lower_bound(frst, last, val) 用来寻找在数组或容器的 [first, last) 范围内第一个值大于等于 val 的元素的位置,如果是数组,则返回该位置的指针;如果是容器,则返回该位置的迭代器。
-
upper_bound(first, last, val) 用来寻找在数组或容器的 [first, last) 范围内第一个值大于 val 的元素的位置,如果是数组,则返回该位置的指针;如果是容器,则返回该位置的选代器。
两重循环加二分,总复杂度为n^2logn
#include<iostream>
#include<algorithm>
#include<string>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
#include<queue>
typedef long long ll;
using namespace std;
const int MOD = 10000007;
const int INF = 0x3f3f3f3f;
const int maxn = 4010;
int a[maxn];
int b[maxn];
int c[maxn];
int d[maxn];
int ab[maxn*maxn];
int main()
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d%d%d%d",&a[i],&b[i],&c[i],&d[i]);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
ab[i*n+j] = a[i]+b[j];
sort(ab,ab+n*n);
int cnt = 0;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
int tmp = c[i]+d[j];
cnt += upper_bound(ab,ab+n*n,-tmp) - lower_bound(ab,ab+n*n,-tmp);
}
}
printf("%d\n",cnt);
return 0;
}