四个数列(二分查找)

问题描述

ZJM 有四个数列 A,B,C,D,每个数列都有 n 个数字。ZJM 从每个数列中各取出一个数,他想知道有多少种方案使得 4 个数的和为 0。

当一个数列中有多个相同的数字的时候,把它们当做不同的数对待。

请你帮帮他吧!

Input

第一行:n(代表数列中数字的个数) (1≤n≤4000)

接下来的 n 行中,第 i 行有四个数字,分别表示数列 A,B,C,D 中的第 i 个数字(数字不超过 2 的 28 次方)

Output

输出不同组合的个数。

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

样例解释: (-45, -27, 42, 30), (26, 30, -10, -46), (-32, 22, 56, -46),(-32, 30, -75, 77), (-32, -54, 56, 30).

解题思路

乍一看是一个暴力枚举题目,但是注意数据范围,n<=4000的范围肯定不能四重循环来枚举。

我们采用先枚举A和B,得到A和B的和ab数组,然后枚举C和D,在枚举C和D的时候,计算它的相反数在ab数组中出现的次数。这样时间复杂度就可以控制在 O ( n 2 ) O(n^2)

那么如何统计次数呢?

map!必须map!key值是A和B中枚举元素的和,对应的element是次数,提交!TLE!很明显,map耗时有点严重。。。

然后我们的unordered_map登场了!这样一个无序map,其耗时比普通的map要少很多!提交!CE!看来这题不支持C++11。。。

后来想起了(翻ppt找到了)学长上课讲的东西,统计出现的次数我们可以先用sort排序,然后二分查找,查找一个数在ab数组中第一次和最后一次出现的位置,做差加一后就是次数。顺利AC。

完整代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <climits>
#include <algorithm>
#include <queue>
#include <vector>
#include <map>
using namespace std;

const int maxn=4000+10;
int a[maxn],b[maxn],c[maxn],d[maxn],n,ans,ab[maxn*maxn],index1;
int getint()
{
    int x=0,s=1;
    char ch=' ';
    while(ch<'0' || ch>'9')
    {
        ch=getchar();
        if(ch=='-') s=-1;
    }
    while(ch>='0' && ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*s;
}
int findfirst(int x)//找到x的第一个位置,找不到返回-1
{
    int left=1,right=index1,anstemp=-1;
    while(left<=right)
    {
        int mid=(left+right)>>1;
        if(ab[mid]==x){
            anstemp=mid;
            right=mid-1;
        }
        else if(ab[mid]<x) left=mid+1;
        else right=mid-1;
    }
    return anstemp;
}
int findend(int x)//找到x的最后一个位置,找不到返回-1
{
    int left=1,right=index1,anstemp=-1;
    while(left<=right)
    {
        int mid=(left+right)>>1;
        if(ab[mid]==x){
            anstemp=mid;
            left=mid+1;
        }
        else if(ab[mid]>x) right=mid-1;
        else left=mid+1;
    }
    return anstemp;
}
int main()
{
//    ios::sync_with_stdio(false);
//    cin.tie(0);

    n=getint();
    for (int i=1; i<=n; i++)
        a[i]=getint(),b[i]=getint(),c[i]=getint(),d[i]=getint();

    for (int i=1; i<=n; i++)
        for (int j=1; j<=n; j++)
            ab[++index1]=a[i]+b[j];

    sort(ab+1,ab+1+index1);

    for (int i=1; i<=n; i++)
        for (int j=1; j<=n; j++)
        {
            int temp=c[i]+d[j];
            int first=findfirst(-temp);
            int end=findend(-temp);
            if(first!=-1)//存在
                ans+=end-first+1;
        }

    printf("%d\n",ans);
    return 0;
}
发布了32 篇原创文章 · 获赞 24 · 访问量 2234

猜你喜欢

转载自blog.csdn.net/weixin_43347376/article/details/104931827
今日推荐