UVA 1152 4 Values Whose Sum is Zero 和为0的4个值

摘要:中途相遇。对比map,快排+二分查找,Hash效率。

n是4000的级别,直接O(n^4)肯定超,所以中途相遇法,O(n^2)的时间枚举其中两个的和,O(n^2)的时间枚举其他两个的和的相反数,然后O(logN)的时间查询是否存在。

首先试了下map,果断TLE

//TLE
#include<cstdio>
#include<algorithm>
#include<map>
using namespace std;

const int maxn = 4001;
int data[4][maxn];

map<int,int> cnt;

int main()
{

    int T ; scanf("%d",&T);
    int *A = data[0], *B = data[1], *C = data[2],*D = data[3];
    map<int,int>::iterator it;
    while(T--){
        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++){
            cnt[A[i]+B[j]]++;
        }

        int ans = 0;
        for(int i = 0; i < n; i++)
        for(int j = 0; j < n; j++){
            int tmp = -C[i]-D[j];
            it = cnt.find(tmp);
            if(it!=cnt.end()) ans += it->second;
        }
        printf("%d\n",ans);
        if(T) putchar(‘\n‘);
    }

    return 0;
}

map,TLE

然后改成了快排+二分查找,4920ms

// runtime 4920ms
#include<cstdio>
#include<algorithm>
using namespace std;

const int maxn = 4001;
int data[4][maxn];
int vec[maxn*maxn];

int _lower_bound(int *A,int L,int R,int v)
{
    int m;
    while(L<R){
        m = (L+R)>>1;
        if(A[m]>=v) R = m;
        else L = m+1;
    }
    return L;
}

int _upper_bound(int *A,int L,int R,int v)
{
    int m;
    while(L<R){
        m = (L+R)>>1;
        if(A[m]>v) R = m;
        else L = m+1;
    }
    return L;
}

int main()
{

    int T ; scanf("%d",&T);
    int *A = data[0], *B = data[1], *C = data[2],*D = data[3];
    while(T--){
        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);
        }

        int sz = 0;
        for(int i = 0; i < n; i++)
        for(int j = 0; j < n; j++){
            vec[sz++] = A[i]+B[j];
        }
        sort(vec,vec+sz);

        int ans = 0;
        for(int i = 0; i < n; i++)
        for(int j = 0; j < n; j++){
            int tmp = -(C[i]+D[j]);
            ans +=  _upper_bound(vec,0,sz,tmp) - _lower_bound(vec,0,sz,tmp);
        }
        printf("%d\n",ans);
        if(T) putchar(‘\n‘);
    }

    return 0;
}

快拍+二分,4920ms

更好一点的做法快排+计数,2832ms

#include<cstdio>
#include<algorithm>
#include<map>
using namespace std;
typedef pair<int,int> pii;
#define fi first
#define se second
const int maxn = 4001;
int data[4][maxn];

pii cnt1[maxn*maxn];
pii cnt2[maxn*maxn];
int vec[maxn*maxn];

int main()
{
    int T ; scanf("%d",&T);
    int *A = data[0], *B = data[1], *C = data[2],*D = data[3];
    while(T--){
        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);
        }
        int sz = 0;
        for(int i = 0; i < n; i++)
        for(int j = 0; j < n; j++){
            vec[sz++] = A[i]+B[j];
        }
        sort(vec,vec+sz);
        int len1 = 0;
        cnt1[len1] = pii(vec[len1],1);
        for(int i = 1; i < sz; i++){
            if(vec[i] == cnt1[len1].fi) cnt1[len1].se++;
            else { cnt1[++len1].fi = vec[i]; cnt1[len1].se = 1; }
        }
        sz = 0;
        for(int i = 0; i < n; i++)
        for(int j = 0; j < n; j++){
            vec[sz++] = -C[i]-D[j];
        }
        sort(vec,vec+sz);
        int len2 = 0;
        cnt2[len2] = pii(vec[len2],1);
        for(int i = 1; i < sz; i++){
            if(vec[i] == cnt2[len2].fi) cnt2[len2].se++;
            else { cnt2[++len2].fi = vec[i]; cnt2[len2].se = 1; }
        }

        int p = 0,q = 0,ans = 0;
        while(p<=len1&&q<=len2){
            if(cnt1[p].fi == cnt2[q].fi){
                ans += cnt1[p++].se*cnt2[q++].se;
            }else if(cnt1[p].fi>cnt2[q].fi) q++;
                  else p++;
        }
        printf("%d\n",ans);
        if(T) putchar(‘\n‘);
    }

    return 0;
}

还有Hash表,写挂了,待补。。。

时间: 2024-07-30 07:47:11

UVA 1152 4 Values Whose Sum is Zero 和为0的4个值的相关文章

(白书训练计划)UVa 1152 4 Values whose Sum is 0(中途相遇法。。)

题目地址:UVa 1152 先枚举A集合与B集合的和,存起来,然后再枚举C集合与D集合的和,看与存起来的值有多少个是互为相反数的.水题.找存起来的值时可以用二分找. 代码如下: #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <stdlib.h> #include <math.h> #include <ctyp

UVA 1152 4 Values whose Sum is 0

题意: 四个集合,要求每个集合中选出一个数字,四个数字相加为0,问四个数字相加为零的次数有几次 分析: 先把A+B的和存到sum数组里,然后再从中找-(c+b)出现的个数.求长度为n的有序数组a中的数k的个数num:num=upper_bound(a,a+n,k)-lower_bound(a,a+n,k); 代码: #include <iostream>#include <cstdio>#include <cstring>#include <algorithm&g

uva 1152 4 values whose sum is zero ——yhx

The SUM problem can be formulated as follows: given four lists A;B;C;D of integer values, computehow many quadruplet (a; b; c; d) 2 AB C D are such that a+b+c+d = 0. In the following, weassume that all lists have the same size n.InputThe input begins

1152 - 4 Values whose Sum is 0(好用的hash标记,多重循环简单化)

不得不说这个题就是炫酷啊! 首先说一说思路吧,是这么想的: 1.弄四重循环,爆破,明显会超时. 2.为了处理多重循环,就枚举a+b+c,只需要在d中找到a+b+c的相反数即可,超时 3.枚举a+b,只需要在c+d中找到a+b的相反数即可,TMD超时! 4.循环只能优化到这个程度了,再优化就得用哈希表直接调用了. 这个题的哈希表也是新的知识,由于本题a+b的值可能很大很大,所以以前的哈希表检索不好用了(因为数组开不了那么大),多亏高神的Blog,学了一招,哈哈,下面是搬运的内容: 对于一个无法用数

1152 - 4 Values whose Sum is 0

紫书上叫中途相遇法,还有一个名字感觉更加妥帖一点,叫:折半枚举.          有时候,当问题的规模较大时,无法枚举所有元素的组合,但能够枚举一半的元素组合,此时,将问题拆成两半后分别枚举,再合并他们的结果这一方法往往非常有效. 两重循环加二分,总复杂度为n^2logn 这里值得一提的是对集合CD的存储方式,我是用了一个有序数组,也可以用其他方式. #include<bits/stdc++.h> using namespace std; const int max_n =4005; int

UVa 1152 4Values whose Sum is 0

题意  从4个n元集中各挑出一个数  使它们的和为零有多少种方法 直接n^4枚举肯定会超时的  可以把两个集合的元素和放在数组里  然后排序 枚举另外两个集合中两元素和  看数组中是否有其相反数就行了  复杂度为n^2*logn #include <bits/stdc++.h> #define l(i) lower_bound(s,s+m,i) #define u(i) upper_bound(s,s+m,i) using namespace std; const int N = 4005;

K - 4 Values whose Sum is 0(中途相遇法)

K - 4 Values whose Sum is 0 Crawling in process... Crawling failed Time Limit:9000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status Practice UVA 1152 Appoint description: System Crawler (2015-03-12) Description The SUM problem can

POJ 2785 4 Values whose Sum is 0(折半枚举)

4 Values whose Sum is 0 Time Limit: 15000MS   Memory Limit: 228000K Total Submissions: 17088   Accepted: 4998 Case Time Limit: 5000MS Description The SUM problem can be formulated as follows: given four lists A, B, C, D of integer values, compute how

uva 11235 - Frequent values(RMQ)

题目链接:uva 11235 - Frequent values 题目大意:给定一个非降序的整数数组,要求计算对于一些询问(i,j),回答ai,ai+1,-,aj中出现最多的数出现的次数. 解题思路:因为序列为非降序的,所以相同的数字肯定是靠在一起的,所以用o(n)的方法处理处每段相同数字的区间.然后对于每次询问: num[i]=num[j]:j?i+1 numi≠numj:max(RMQ(righti+1,reftj?1),max(righti?i+1,j?leftj+1)) #include