POJ2785-4 Values whose Sum is 0
纯暴力是n^4果断超时。本题得解法可以采用二分搜索。时间复杂度n^2(logn)的样子,空间复杂度n^2。虽然还是非常巨大,但是本题可以险过,时间大概5s。
采用两个数组a[],b[]分别记录前两列所有可能的和与后两列所有可能的和,N^2级。然后对两个数组排序,便于统计每个值出现的次数,每个数组变为了两个数组,一个保存所有可能的值,只保存一个,仍为a[],另设一个数组c[],c[i]==(a[i]的个数)。b,d类似。然后对a中每一个数a[i]在b内二分搜索a[i]*(-1),如果存在b[j] == a[i]*(-1),返回d[j],没有就返回0。如果返回值不为0则总数加上d[j]*c[i]。
#include <iostream> #include <algorithm> #include <string.h> #include <cstring> #include <cmath> #include <cstdio> using namespace std; /* * 预处理+二分搜索 */ const int N = 16000005; int a[N], b[N], c[N], d[N]; int p[4005][4]; //二分搜索一个值在b数组中的个数 int search(int n, int x){ // int l = 0, r = n - 1, mid; while (l <= r){ mid = (l + r) / 2; if (b[mid] == x) return d[mid]; else if (b[mid] < x)l = mid + 1; else r = mid - 1; } return 0; } int main(){ int n, k; while (scanf("%d", &n) != EOF){ for (int i = 0; i < n; i++) for (int j = 0; j < 4; j++) scanf("%d", &p[i][j]); //a保存前两列可能的和,b保存后两列可能的和 k = 0; for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) a[k++] = p[i][0] + p[j][1]; k = 0; for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) b[k++] = p[i][2] + p[j][3]; sort(a, a + k);//排序 sort(b, b + k);//【排序 int t = 0, h = 0; c[0] = d[0] = 1; //对数组a预处理,如果存在重复则记录这个值重复的次数 //而且重复的值只保留一个 for (int i = 1; i < k; i++){ if (a[i] == a[t]) c[t]++; else { t++; a[t] = a[i]; c[t] = 1; } } //b类似 for (int i = 1; i < k; i++){ if (b[i] == b[h]) d[h]++; else { h++; b[h] = b[i]; d[h] = 1; } } __int64 sum = 0; for (int i = 0; i <= t; i++){ sum += search(h + 1, a[i] * (-1)) * c[i]; } printf("%I64d\n", sum); } return 0; }