4 Values whose Sum is 0 POJ - 2785 & Can you find it? HDU - 2141(二分)

4 Values whose Sum is 0
Time Limit: 15000MS Memory Limit: 228000K
Total Submissions: 26489 Accepted: 7976
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 many quadruplet (a, b, c, d ) ∈ A x B x C x D are such that a + b + c + d = 0 . In the following, we assume that all lists have the same size n .

Input

The first line of the input file contains the size of the lists n (this value can be as large as 4000). We then have n lines containing four integer values (with absolute value as large as 2 28 ) that belong respectively to A, B, C and D .

Output

For each input file, your program has to write the number quadruplets whose sum is zero.

Sample Input

6
-45 22 42 -16
-41 -27 56 30
-36 53 -37 77
-36 30 -75 -46
26 -38 -10 62
-32 -54 -6 45

Sample Output

5

Hint

Sample Explanation: Indeed, the sum of the five following quadruplets is zero: (-45, -27, 42, 30), (26, 30, -10, -46), (-32, 22, 56, -46),(-32, 30, -75, 77), (-32, -54, 56, 30).

Source

[Submit]   [Go Back]   [Status]   [Discuss]

题意:给你四列数,问从这四列数中各选一个数使他们的和是0的情况有多少种?

思路:二分找答案,先将前两列数分别加起来存到一个新的数组sum里,然后再遍历后两列的数的和,看从sum数组中是否能找到他们的相反数,如果有就让ans+1;

//直接利用二分函数
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<stack>
#define inf 0x3fffffff
using namespace std;
typedef long long LL;
const double eps=1e-8;
const double pi=acos(-1);
const int N=4e3+1;
int n,a[N],b[N],c[N],d[N],s[N*N],tot;
int finf(int x)
{
    int l=lower_bound(s,s+tot,x)-s;
    int r=upper_bound(s,s+tot,x)-s;
    return r-l;
}
int main()
{
    tot=0;
    int ans=0;
    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++)
            s[tot++]=a[i]+b[j];
    sort(s,s+tot);
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            ans+=finf(-(c[i]+d[j]));
    printf("%d\n",ans);
}
 
//自己写二分查找
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<stack>
#define inf 0x3fffffff
using namespace std;
typedef long long LL;
const double eps=1e-8;
const double pi=acos(-1);
const int N=4e3+1;
int n,a[N],b[N],c[N],d[N],s[N*N],tot;
int finf(int x)
{
    int ansl,ansr,mid;
    int l=0,r=tot;
    while(l<r)
    {
        mid=(l+r)/2;
        if(s[mid]>=x) r=mid;
        else l=mid+1;
    }
    ansl=l;
    l=0,r=tot;
    while(l<r)
    {
        mid=(l+r)/2;
        if(s[mid]>x) r=mid;
        else l=mid+1;
    }
    ansr=l;
    return ansr-ansl;
}
int main()
{
    tot=0;
    int ans=0;
    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++)
            s[tot++]=a[i]+b[j];
    sort(s,s+tot);
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            ans+=finf(-(c[i]+d[j]));
    printf("%d\n",ans);
}



 
那我们再接着来看一道一模一样的题: 

Can you find it?

Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 32768/10000 K (Java/Others)Total Submission(s): 37412    Accepted Submission(s): 9145
Problem Description
Give you three sequences of numbers A, B, C, then we give you a number X. Now you need to calculate if you can find the three numbers Ai, Bj, Ck, which satisfy the formula Ai+Bj+Ck = X.
 
Input
There are many cases. Every data case is described as followed: In the first line there are three integers L, N, M, in the second line there are L integers represent the sequence A, in the third line there are N integers represent the sequences B, in the forth line there are M integers represent the sequence C. In the fifth line there is an integer S represents there are S integers X to be calculated. 1<=L, N, M<=500, 1<=S<=1000. all the integers are 32-integers.
 
Output
For each case, firstly you have to print the case number as the form "Case d:", then for the S queries, you calculate if the formula can be satisfied or not. If satisfied, you print "YES", otherwise print "NO".
 
Sample Input
 
 
3 3 31 2 31 2 31 2 331410
 

Sample Output
 
 
Case 1:NOYESNO
 
Author
wangye
 
Source
 
Recommend
威士忌
 题意:给你三列数,然后n次查询,每次给出一个数,问是否能从那三列数中各选出一个使得他们的和等于这个数,如果能输出YES,否则NO。心路历程:是不是很简单啊,确实很简单啊,不是跟上面的一模一样的吗?这两道题分别出现在这三天的两场比赛中,中间只隔了一天,看到这题的时候内心很是激动,因为上一场刚刚出现过所以印象还是非常清晰的,代码也很快就写出来了,但是一交MLE????这种情况没遇到过几次,当时有点懵,然后算了一下空间复杂度,好像确实超了(我的新的sum数组里存的是三个数列的各种情况的和,要开n*n*n大小的数组,n<=500,题目内存只给了10000 kB,确实会超),然后我同样用map存三个数列的各种情况 的和还是MLE,当时认真想了一下,既然存三个数列的和的情况会MLE,那就存先两个数列的各种情况和呗,但我依旧用的是map来操作,so 结果依旧是MLE,这个时候就有点绝望了,这都不行,算了一下空间感觉够啊(不知道map里面的空间会占多少?),比赛的时候就是没有再用二分试一下存两个数列的各种情况的和,比赛刚结束我问旁边的伙伴,他说用二分存前两列的各种情况和我就恍然大悟,,,,,,,,,啊,又一次和AC擦肩而过,多么好的AC机会啊,多么痛的领悟啊!!!!!!!!!!!!以后比赛如果遇到这种情况,一定要把所有想到情况都是一遍,不要怕wa,不要怕罚时,反正已经罚时爆炸了,怕什么微笑微笑
接下来就直接看代码吧:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<vector>
#define inf 0x3fffffff
using namespace std;
typedef long long LL;
const double eps=1e-8;
const double pi=acos(-1);
const int N=502;
int aa,bb,cc,tot;
LL a[N],b[N],c[N],sum[N*N];
int main()
{
    int s,d,t=1,ans,flag;
    while(~scanf("%d%d%d",&aa,&bb,&cc))
    {
        tot=flag=0;
        for(int i=0;i<aa;i++)
            scanf("%I64d",&a[i]);
        for(int i=0;i<bb;i++)
            scanf("%I64d",&b[i]);
        for(int i=0;i<cc;i++)
            scanf("%I64d",&c[i]);
        for(int i=0;i<aa;i++)
            for(int j=0;j<bb;j++)
                sum[tot++]=a[i]+b[j];
        sort(sum,sum+tot);
        scanf("%d",&s);
        printf("Case %d:\n",t++);
        while(s--)
        {
            scanf("%d",&d);
            flag=0;
            for(int i=0;i<cc;i++)
            {
                ans=lower_bound(sum,sum+tot,d-c[i])-sum;
                if(sum[ans]==d-c[i])
                {
                    flag=1;
                    printf("YES\n");
                    break;
                }
            }
            if(!flag) printf("NO\n");
        }
    }
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值