四个数列
题目要求
ZJM 有四个数列 A,B,C,D,每个数列都有 n 个数字。ZJM 从每个数列中各取出一个数,他想知道有多少种方案使得 4 个数的和为 0。
当一个数列中有多个相同的数字的时候,把它们当做不同的数对待。
请你帮帮他吧!
Input
第一行:n(代表数列中数字的个数) (1≤n≤4000)
接下来的 n 行中,第 i 行有四个数字,分别表示数列 A,B,C,D 中的第 i 个数字(数字不超过 2 的 28 次方)
Output
输出不同组合的个数。
求解思路
如果直接暴力求解,算法复杂度将达到n4。而先计算出A、B队列的n2种组合,再利用二分查找的方式对于C、D队列的每种组合计算出A、B队列中符合要求的组合数目x,最后把所有x求和即为组合个数。这样复杂度为n2logn2
在计算出A、B队列中符合要求的组合数目x时,使用了二分查找的方法,查找出队列中最后一个符合要求的元素的位置和第一个符合要求的位置,二者相减加一即为x
代码
#include<iostream>
#include<algorithm>
#include<stdio.h>
using namespace std;
int a[4001];
int b[4001];
int c[4001];
int d[4001];
int ab[16000001];
int n;
int find(int x)
{
int difference = 0;
int l = 0, r = n*n-1, ans = -1;
while (l <= r)
{
int middle = (l + r) >> 1;
if (ab[middle] == x)
{
ans = middle;
l = middle + 1;
// cout << "a";
}
else if (ab[middle] > x) r = middle - 1;
else l = middle + 1;
}
// cout << ans;
if (ans == -1)//x最后一个位置
{
return 0;
}
difference = ans;
l = 0; r = n*n-1; ans = -1;
while (l <= r)
{
int middle = (l + r) >> 1;
if (ab[middle] == x)
{
ans = middle;
r = middle - 1;
}
else if (ab[middle] > x) r = middle - 1;
else l = middle + 1;
}//x最前的一个位置
difference = difference - ans + 1;
return difference;
}
int main()
{
cin >> n;
for (int i = 0; i < n; i++)
{
// scanf("%d%d%d%d", &a[i], &b[i], &c[i], &d[i]);
cin >> a[i] >> b[i] >> c[i] >> d[i];
}
for(int j=0;j<n;j++)
for (int k = 0; k < n; k++)
ab[j * n + k] = a[j] + b[k];
sort(ab, ab + n * n);
int sum = 0;
for (int j = 0; j < n; j++)
{
for (int k = 0; k < n; k++)
{
int cd = c[j] + d[k];
cd = cd * (-1);
// cout << cd << endl;
sum += find(cd);
}
}
// for (int j = 0; j < n; j++)
// for (int k = 0; k < n; k++)
// cout << ab[j * n + k] << endl;
printf("%d", sum);
return 0;
}