题目链接: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 imes 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 <bits/stdc++.h>
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;
}