CF978C Letters 题解 二分

题目链接:http://codeforces.com/problemset/problem/978/C

题目描述(人名、地名略有改编)

在学校里有 \(n\) 个寝室楼,寝室楼的编号从 \(1\)\(n\) 。第 \(i\) 号寝室楼例有 \(a_i\) 个房间,房间编号从 \(1\)\(a_i\)
聪聪最近做了学校里这个片区的邮递员。
但是令他困惑的是:学校里的学生们在填写收货地址的时候,采用了另外一种地址标记方式。
他们填写的收货地址是一个数字,但是这个数字并不能直接表示是哪个寝室楼的哪个房间。
地址的编号从 \(1\)\(a_1 + a_2 + \cdots + a_n\)
其中:

  • \(1\) 号寝室楼的第 \(i\) 个房间的收件地址对应的编号是 \(i\)
  • \(2\) 号寝室楼的第 \(i\) 个房间的收件地址对应的编号是 \(a_1 + i\)
  • \(3\) 号寝室楼的第 \(i\) 个房间的收件地址对应的编号是 \(a_1 + a_2 + i\)
  • …………

按照这么类推,最后一个写字楼(也就是第 \(n\) 号写字楼)的最后一个房间(也就是第 \(a_n\) 个房间)对应的编号就是:

\(a_1 + a_2 + \cdots + a_n\)

今天聪聪有 \(m\) 个包裹要派发,但是他只知道这 \(m\) 个包裹对应的收件地址,分别为 \(b_1\), \(b_2\), …… ,\(b_m\)
但是他不知道某一个包裹 \(b_j\) 对应的楼号和房间号,请你帮忙计算一下。

输入格式

输入的第一行包含两个整数 \(n\)\(m\) ,分别表示 寝室楼的数量 和 包裹的数量。( \(1 \le n,m \le 2 \times 10^5\)
第二行包含 \(n\) 个整数构成的整数序列 \(a_1,a_2, \cdots ,a_n\)\(1 \le ai \le 10^{10}\)),以空格分隔,其中 \(a_i\) 用于表示第 \(i\) 号寝室楼中房间的数量。
第三行包含 \(m\) 个整数构成的整数序列 \(b_1,b_2, \cdots ,b_m\)\(1 \le bj \le a_1+a_2+ \cdots +a_n\)),以空格分隔,其中 \(b_j\) 用于表示第 \(j\) 个包裹对应的收货地址。
题目保证所有的 \(b_j\) 是按照递增的顺序给你的。

输出格式

输出 \(m\) 行。每行包含两个整数,以一个空格分隔,分别表示该包裹所在的寝室楼的楼号 \(f\)\(1 \le f \le n\) ) 以及房间号 \(k\)\(1 \le k \le a_f\))。

题目分析

这道题目涉及的算法:二分。
首先要二分的话,我们要实现一个单调性的数组 \(sum[]\)\(sum[i]\) 用于表示 \(a[1]\)\(a[i]\) 的和。
求解 \(sum[i]\) 也很简单,开个 for 循环, \(sum[i] = sum[i-1] + a[i]\)
然后对于每一个 \(b_j\) 我们就可以通过二分 \(sum\) 求得 \(b_j\) 在哪一号寝室楼。
然后对于 \(b_j\) 来说,我们找到了它的寝室号 \(f\) ,那么他的房间号就是 \(b_j - a[f-1]\)
实现代码如下:

#include 
using namespace std;
const int maxn = 200020;
int n, m;
long long a[maxn], b, sum[maxn];

int main() {
    cin >> n >> m;
    for (int i = 1; i <= n; i ++) {
        cin >> a[i];
        sum[i] = sum[i-1] + a[i];
    }
    while (m --) {
        cin >> b;
        int f = lower_bound(sum+1, sum+1+n, b) - sum;
        long long k = b - sum[f-1];
        cout << f << " " << k << endl;
    }
    return 0;
}

你可能感兴趣的:(CF978C Letters 题解 二分)