A1044 Shopping in Mars(二分/upper_bound)

题目描述

给定长度为n的数组和整数S,求出数组中所有和为S的连续子序列的区间下标(若没有,则求出所有和值正好大于S的子序列下标),下标从1开始。

这道题处理起来有些麻烦,很容易漏解,代码参考了算法笔记中的思路,使用了upper_bound函数,书中是自己写了upper_bound函数,我直接使用了algorithm中的upper_bound函数,下面分别放出代码:

书中:

#include
using namespace std;
const int N=100005;
int n,S;
int sum[N];
int nearS=100000010;

//返回在[L,R)内第一个大于x的位置
int upper_bound(int L,int R,int x)
{
    int left=L,right=R,mid;
    while(left<right)
    {
        mid=(left+right)/2;
        if(sum[mid]>x)
            right=mid;
        else
            left=mid+1;
    }
    return left;
}

int main()
{
    scanf("%d%d",&n,&S);
    sum[0]=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&sum[i]);
        sum[i]+=sum[i-1];
    }
    for(int i=1;i<=n;i++)
    {
        int j=upper_bound(i,n+1,sum[i-1]+S);
        if((sum[j-1]-sum[i-1])==S){//注意是j-1不是j
            nearS=S;
            break;
        }
        else if(j<=n&&(sum[j]-sum[i-1])<nearS){
            nearS=sum[j]-sum[i-1];
        }
    }
    for(int i=1;i<=n;i++)
    {
        int j=upper_bound(i,n+1,sum[i-1]+S);
        if((sum[j-1]-sum[i-1])==nearS)
            printf("%d-%d\n",i,j-1);
    }
    return 0;
}

我自己写的:

#include
#include
using namespace std;
const int maxn=100005;
int n,m;
int sum[maxn];
int temp=1e8+10;
int main()
{
    scanf("%d%d",&n,&m);
    sum[0]=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&sum[i]);
        sum[i]+=sum[i-1];//这个很巧妙,自己没有想到,把数组直接初始化为前n个数之和
    }
    for(int i=1;i<=n;i++)
    {
        int j=upper_bound(sum+i,sum+n,sum[i-1]+m)-sum;
        if((sum[j-1]-sum[i-1])==m){//注意是j-1不是j
            temp=m;
            break;
        }
        else if(j==n&&(sum[j]-sum[i-1])>=m&&(sum[j]-sum[i-1])<temp){//若upper_bound搜到最后,返回的j是n+1
            temp=sum[j]-sum[i-1];//此时sum[j-1]-sum[i-1]一定大于m,故使用的是j不是j-1
        }
    }
    for(int i=1;i<=n;i++)
    {
        int j=upper_bound(sum+i,sum+n,sum[i-1]+temp)-sum;
        if((sum[j-1]-sum[i-1])==temp)
            printf("%d-%d\n",i,j-1);
        else if(sum[j]-sum[i-1]==temp)//特例:数组最后一个数满足等于m,此时i为n,j为n,但是不能满足sum[j-1]-sum[i-1])==temp
            printf("%d-%d\n",i,j);
    }
    return 0;

}

可见自己写的upper_bound函数在这道题中比自带的upper_bound函数更为强大。在自带中,最多返回到n,而自写的由于右边是开区间,所以可以返回到n+1,这为后面判断起来增加了不少便捷。
以范例为例:输入3 5 2 2 2
自带upper_bound执行后产生的i-j结果为:1-3,2-3,3-3
而自写upper_bound执行后产生的i-j结果为:1-3,2-4,3-4

关于upper_bound和lower_bound的问题以后会再开文章讨论

你可能感兴趣的:(++题)