Uva 1152 和为0的4个值 hash/二分

题意:

给定4个n(1 <= n <= 4000)元素集合A, B, C, D,要求分别从中选取一个元素a, b, c, d,使得a+b+c+d = 0,问有多少种选法。

分析:

显然四重循环是过不了的,我先想到的是用map把a+b,c+d分别保存起来,然后在查找统计。超时。。。。

然后书上说用哈希表去实现,看到有的题解hash表示的太巧妙了,学习一下。

还有就是这题可以用二分解决,先计算出a+b,然后枚举c+d,然后二分找出范围即可。

hash 630ms:

#include<cstdio>
#include<cstring>
const int N=4005;
int a[4][N];
struct Hash_map
{
    static const int mask=0x7fffff;
    int p[mask+1],q[mask+1];
    void clear()
    {
        memset(q,0,sizeof(q));
    }
    int& operator [](int k)
    {
        int i;
        for(i=k&mask;q[i]&&p[i]!=k;i=(i+1)&mask);
        p[i]=k;
        return q[i];
    }
};
Hash_map Hash;
int main()
{
    int T;scanf("%d",&T);
    for(int t=0;t<T;t++){
        int n;
        scanf("%d",&n);
        for(int j=0;j<n;j++)
            for(int i=0;i<4;i++)scanf("%d",&a[i][j]);
        Hash.clear();
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
            Hash[a[0][i]+a[1][j]]++;
        int ans=0;
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
            ans+=Hash[-a[2][i]-a[3][j]];
        if(t)printf("\n");
        printf("%d\n",ans);
    }
    return 0;
}

二分 、2720ms:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=4005;
int a[4][N];
int sum[N*N];
int main()
{
    int T;scanf("%d",&T);
    for(int t=0;t<T;t++){
        int n;
        scanf("%d",&n);
        for(int j=0;j<n;j++)
            for(int i=0;i<4;i++)scanf("%d",&a[i][j]);
        int cnt=0;
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
            sum[cnt++]=a[0][i]+a[1][j];
        int ans=0;
        sort(sum,sum+cnt);
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
            ans+=upper_bound(sum,sum+cnt,-a[2][i]-a[3][j])-lower_bound(sum,sum+cnt,-a[2][i]-a[3][j]);
        if(t)printf("\n");
        printf("%d\n",ans);
    }
    return 0;
}
时间: 2024-08-29 18:35:41

Uva 1152 和为0的4个值 hash/二分的相关文章

UVa 1152 和为0的4个值(二分查找)

https://vjudge.net/problem/UVA-1152 题意:给定4个n元素集合A,B,C,D,要求分别从中选取一个元素a,b,c,d,使得a+b+c+d=0.问有多少种取法. 思路:直接暴力枚举的话是会超时的.可以选把a+b的值枚举出来存储,c和d的值也一样并排序,这样就可以在c和d中进行二分查找了. 1 #include<iostream> 2 #include<algorithm> 3 using namespace std; 4 5 const int ma

(白书训练计划)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

js 判断 0&lt;15&lt;30返回值是 true

与java不一样,因为js是弱语言 0<15 返回布尔类型 true,表达式变成true<30, js 有默认类型转换机制,表达式true<30 中的true会 转换成number类型 1,从而变成1< 30,就得到true; 总结:一般不要适应,if(0<15<30)这种,一般用&&  或者 || : js中null,NaN,'',undefined,false,0都为false,js中的对象,数值出了0都为true, var x={o:0,p:1,q

matlab(8) Regularized logistic regression : 不同的λ(0,1,10,100)值对regularization的影响,对应不同的decision boundary\ 预测新的值和计算模型的精度predict.m

不同的λ(0,1,10,100)值对regularization的影响\ 预测新的值和计算模型的精度 %% ============= Part 2: Regularization and Accuracies =============% Optional Exercise:% In this part, you will get to try different values of lambda and % see how regularization affects the decisio

js 数组排序要注意的问题,返回的值最好为 -1, 0, 1之间的值

var test10Elements = [7, 6, 5, 4, 3, 2, 1, 0, 8, 9]; var comparefn = function (x, y) { return x - y; }; test10Elements.sort(comparefn); var comparefn2 = function (x, y) { return x > y; }; test10Elements.sort(comparefn2); http://w3help.org/zh-cn/cause

字符加上&#39;0&#39;等于ascii码值48, 不加引号0等于数值0

'\0'不是指ASCII码值, 它是字符, 它的ASCII码值是0 '\0'==0 0 数字 48 空格 ASCII码值是32 main() { char a='\0'; if(a==0) printf("A ASCII is 0\n"); if(a==' ') printf("A is space\n"); printf("*%c*\n",a); getch(); } 单引号是字符 双引号是字符串 什么都不加是数字 加单引号的表示字符零,即ch

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;

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 0

题意: 要从四个数组中各选一个数,使得这四个数之和为0,求合法的方案数. 分析: 首先枚举A+B所有可能的值,排序. 然后枚举所有-C-D的值在其中用二分法查找. 1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 5 const int maxn = 4000 + 10; 6 int A[maxn], B[maxn], C[maxn], D[maxn], sum[maxn*maxn], cnt;