Codeforces Round #271 (Div. 2) B Worms 裸的二分查找

B. Worms
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

It is lunch time for Mole. His friend, Marmot, prepared him a nice game for lunch.

Marmot brought Mole n ordered piles of worms such that i-th pile contains ai worms. He labeled all these worms with consecutive integers: worms in first pile are labeled with numbers 1 to a1, worms in second pile are labeled with numbers a1 + 1 to a1 + a2 and so on. See the example for a better understanding.

Mole can't eat all the worms (Marmot brought a lot) and, as we all know, Mole is blind, so Marmot tells him the labels of the best juicy worms. Marmot will only give Mole a worm if Mole says correctly in which pile this worm is contained.

Poor Mole asks for your help. For all juicy worms said by Marmot, tell Mole the correct answers.

Input

The first line contains a single integer n (1 ≤ n ≤ 105), the number of piles.

The second line contains n integers a1, a2, ..., an (1 ≤ ai ≤ 103a1 + a2 + ... + an ≤ 106), where ai is the number of worms in the i-th pile.

The third line contains single integer m (1 ≤ m ≤ 105), the number of juicy worms said by Marmot.

The fourth line contains m integers q1, q2, ..., qm (1 ≤ qi ≤ a1 + a2 + ... + an), the labels of the juicy worms.

Output

Print m lines to the standard output. The i-th line should contain an integer, representing the number of the pile where the worm labeled with the number qi is.

Sample test(s)
input
5
2 7 3 4 9
3
1 25 11
output
1
5
3


给n个数,其对应一个前缀数组,

再给m个查询,每个查询是一个数,求出该数所在前缀的下标


就是一个裸的二分查找,但是自从田田学长讲过我们的方法是错的以后

一直以来二分都有点不太清楚,所以这里要记录一下


先看代码:

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <memory.h>
#include <string>
#include <vector>
#include <list>
#include <map>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <numeric>
#include <functional>
#define maxn 100005

using namespace std;
int n;
int m;
int a[maxn];

int binsearch(int tofind)
{
    int high=n,low=1;
    if(tofind<=a[1]) return 1;
    while(1){
        int mid=(high+low+1)/2;
        if(high==low+1) return high;
        else if(a[mid]==tofind) return mid;
        else if(a[mid]>tofind){
            high=mid;
        }
        else if(a[mid]<tofind){
            low=mid;
        }
    }
}

int main()
{
    cin>>n;
    for(int i=1;i<=n;i+=1){
        cin>>a[i];
        if(i>1)
            a[i]+=a[i-1];
    }
    cin>>m;
    for(int j=0;j<m;j+=1){
        int k;
        cin>>k;
        cout<<binsearch(k)<<endl;
    }
    return 0;
}




可以看到与我们以前写的不一样的地方,就是

int mid=(high+low+1)/2;
还有

if(high==low+1) return high;

        else if(a[mid]>tofind){
            high=mid;
        }
        else if(a[mid]<tofind){
            low=mid;
        }

也就是,high和low是直接等于mid的,而最关键的还是第一句 mid=(high+low+1)/2;

二分查找无分三种情况

(1)找到a[mid]=tofind;

(2)夹在某三个 a[n+1] a[n] a[n-1] 之间,分别是h,m,l ,接着就会出现在a[n+1] a[n](l=m)或者是在 a[n] a[n-1](h=m)之间的情况,

这个时候因为要求所在前缀,直接取较大的那个就好了


总结一下,如果仅仅是判断某个数组内是否有某个数,那么可以用以前的这种写法:

int binsearch(int tofind)
{
    int high=n,low=1;
    if(tofind<=a[1]) return 1;
    while(1){
        int mid=(high+low)/2;
        if(high==low) return -1;
        else if(a[mid]==tofind) return mid;
        else if(a[mid]>tofind){
            high=mid-1;
        }
        else if(a[mid]<tofind){
            low=mid+1;
        }
    }
}

而如果想要求解在哪个前缀中,则应该使用这个写法:

int binsearch(int tofind)
{
    int high=n,low=1;
    if(tofind<=a[1]) return 1;
    while(1){
        int mid=(high+low+1)/2;
        if(high==low+1) return high;
        else if(a[mid]==tofind) return mid;
        else if(a[mid]>tofind){
            high=mid;
        }
        else if(a[mid]<tofind){
            low=mid;
        }
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值