Week4作业 B - 四个数列

问题描述:

给四个数列A,B,C,D,每个数列各有n个数(𝑛 ≤ 4000)。从每个数列中各取出一个数,问有多少种方案使得4个数的和为0。当一 个数列中有多个相同的数字的时候,把它们当做不同的数对待。其中,数字不超过 2 的 28 次方。

思路:

枚举A+B的和并存储,然后枚举C+D的和,当ci+di的相反数在ai+bi中出现过k次时,答案就加k。

如何找ci+di的相反数出现过几次?起初的方案是用桶,但是2^28=1e8,而且主要的问题是有可能出现负数,但数组下标用负数就不和谐了。

用map的话,每次查询logn,超时!!?但是为什么二分不超时?都是logn啊

我尝试使用之前讲过的unordered_map,并且包含了头文件map和unordered_map,本地测试样例通过,但是VJ上C++和G++都CE,失败的尝试。

最后用二分求了左右边界,然后相减得出的结果。

后来又查阅了STL,精简(偷懒)了一下代码

代码:

#include <cstdio>
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
//#include <unordered_map>
using namespace std;
const int MAXN=5e5+5;
vector<int> sum;
int a[MAXN],b[MAXN],c[MAXN],d[MAXN];
int find(int x)   //在有序序列中找x出现的次数 
{
    int l=0,r=sum.size()-1,lans=-1,rans=-1;   
    while(l<=r)        //找第一次出现
    {
        int mid=(l+r)/2;
        if(sum[mid]==x) lans=mid,r=mid-1;
        else if(sum[mid]>x) r=mid-1; 
        else l=mid+1;
    }
    if(lans==-1) return 0;
    l=0,r=sum.size()-1;
    while(l<=r)        //找最后一次出现 
    {
        int mid=(l+r)/2;
        if(sum[mid]==x) rans=mid,l=mid+1;
        else if(sum[mid]>x) r=mid-1;
        else l=mid+1; 
    }
    return rans-lans+1;
}
int main()
{
    int n; cin>>n;
    for(int i=0;i<n;i++)
        scanf("%d %d %d %d",a+i,b+i,c+i,d+i);
    
    int ans=0;
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
        {
            sum.push_back( a[i]+b[j] );
        }
    sort( sum.begin(),sum.end() ); 
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
        {
            ans+=find( -( c[i]+d[j] ) );
        }
    cout<<ans<<endl;
    return 0;
}
View Code

总结:

1、静态区开大数组, 一般的写法是:

const int MAXN=1e6+5;
int v[MAXN];

2、STL中的二分查找

①binary_search:

//存在VAL则返回true,否则返回false,区间左闭右开[first,last)
bool binary_search (ForwardIterator first, ForwardIterator last, const T& val)

②lower_bound:

//二分求下界,返回第一个大于等于val的位置
ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last, const T& val)

③upper_bound:

//二分求上界,返回第一个大于val的位置
ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last, const T& val)

 当val不存在时,lower_bound()和upper_bound()返回相同的值,都是第一个大于val的位置

3、用STL改写了的代码:

#include <cstdio>
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
//#include <unordered_map>
using namespace std;
vector<int> sum;

int a[5005],b[5005],c[5005],d[5005];
int find(int x)   //在有序序列中找x出现的次数 
{
    //不能直接用int *p=upper_bound(sum.begin(),sum.end(),x);  因为返回的不是int*类型 
    return upper_bound(sum.begin(),sum.end(),x)-lower_bound(sum.begin(),sum.end(),x);
}
int main()
{
    int n; cin>>n;
    for(int i=0;i<n;i++)
        scanf("%d %d %d %d",a+i,b+i,c+i,d+i);
    
    int ans=0;
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
        {
            sum.push_back( a[i]+b[j] );
        }
    sort( sum.begin(),sum.end() ); 
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
        {
            ans+=find( -( c[i]+d[j] ) );
        }
    cout<<ans<<endl;
    return 0;
}
View Code

 

posted @ 2020-03-15 17:38  菜鸡今天学习了吗  阅读(145)  评论(0编辑  收藏  举报