Two Point I (简单的二分应用)

题目描述

有两个从小到大排好序的序号a和b,长度均为n。
要求选择两个数i、j,满足a[i]+b[j]<=m的情况令a[i]+b[j]尽可能大。输出a[i]+b[j]的最大值

输入

输入一个正整数n、m,表示数组的长度、m如上面题面所说 。
第2行输入a数组。
第3行输入b数组。

输出

输出答案。

样例输入

复制样例数据

4 10
1 3 5 9
2 8 9 10

样例输出

10

提示

100%的数据满足:1 ≤ n ≤ 1,000,000.
所有数保证大小∈[1,1000000000].

 题干含有如下关键条件:

  1.  两个数组都是有序的。
  2. 从a[i]中选择一个数,再从b[j]中选择一个数。
  3. m内尽可能大。
  4. 两个数组的长度最大为1e6。

用最朴素的算法就是对于每一个a[i],都要遍历一遍b[i]来判断一下a[i]+b[j]与m的关系。是O(n^2)的复杂度,极限数据为复杂度为1e12,显然大量超时。

根据题目中有序的条件,我们可以把某一个循环优化为二分查找,这样极限复杂度被降为了1e6*log2(1e6),在1.8e7~2.4e7之间。满足了时间复杂度的限制。

#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
#include <algorithm>
#include <iomanip>
#include <cstring>
#include <cmath>
//#include <minmax.h>
#define DETERMINATION main
#define lldin(a) scanf("%lld",&a)
#define din(a) scanf("%d",&a)
#define reset(a,b) memset(a,b,sizeof(a))
const int INF=0x3f3f3f3f;
const int LIM=1e7+356;
using namespace std;
typedef long long ll;
/**you can feel the pulse of your destiny...
The nervous feeling fills you with determination.**/
int a[LIM],b[LIM];
int DETERMINATION()
{
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
      cin>>a[i];
    for(int i=1;i<=n;i++)
      cin>>b[i];
    int ans=0;
    int l=1,r=n;
    for(int i=1;i<=n;i++)//第一个循环采用朴素遍历
    {
       l=1,r=n;
       while(l<=r)//第二个循环优化为二分查找
       {
          int mid=(l+r)>>1;
          if(b[mid]+a[i]<=m)
          {
              ans=max(a[i]+b[mid],ans);
              l=mid+1;
          }
          else
          {
            r=mid-1;
          }
       }
    }
    cout<<ans<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43874261/article/details/88770356