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;
}
 
posted @ 2011-08-03 20:42  like@neu  阅读(161)  评论(0编辑  收藏  举报