题目链接: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;
}