题目链接:https://ac.nowcoder.com/acm/contest/940/J/
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
andy又开始种树了,他觉得老用魔法不太好,这次他决定老老实实地每天种一棵树,第i天种一颗高度为hi的树,按理说老老实实种树就完事了,哪有那么多问题呢?但是他们学校有个叫kotori的人,非常爱砍树,每天都会把所有andy已经种下的树砍掉ci,如果第i天的时候某棵树的高度已经小于等于ci了,那么这棵树就会死亡,以后再也不会被砍了。并且如果到了第n天,有一些树还没被砍,那么kotori就会在第n + 1天把这些树全部砍死。
输入描述
第一行输入一个整数n,表示andy会种n天的树。
第二行含有n个数hi,表示andy在第i天种的树的高度为hi米。
第三行含有n个ci,表示kotori在第i天把所有andy已经种下的树砍掉ci。
1 <= n, hi, ci <= 1e5
输出描述
输出一行n个数di,每个数后面有一个空格(包括最后一个数),最后需要换行。
表示andy第i天种的树会在第di天死亡,如果第n天这棵树还没有死亡,则输出n + 1。
输入
10
5 7 5 4 1 7 4 3 10 6
6 4 2 4 1 8 5 7 3 5
输出
1 4 4 4 5 6 7 8 11 11
说明
第1天andy种的树高度为5,这天kotori要把andy已经种下的所有树砍掉6,所以第1棵树在第1天就死掉了。
第2天andy种的树高度为7,第2天被kotori砍掉了4,还剩3,第3天被kotori砍掉了2,还剩1。第4天被砍掉4,所以它在第4天死亡。
第10天andy种下的数高度为6,第10天被kotori砍掉了5,还剩1,也就是说它在第10天还没有死亡,所以它会在第11天被kotori砍死(参见题目描述最后一句)。
解题思路
题意:每天都要种树,每天也要砍树,求n棵树将在哪天被砍死。
思路:对位置i,应该找i~n+1中c[i]前缀和超过h[j]的最小位置。因此要求出c的前缀和c,二分查找c[j-1]=h[j]的最小位置。
Accepted Code:
#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
long long c[N], h[N];
int slove(int l, int r, long long k) {
int mid;
while (l <= r) {
mid = (l + r) >> 1;
if (c[mid] >= k)
r = mid - 1;
else l = mid + 1;
}
return l;
}
int main() {
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%lld", &h[i]);
for (int i = 1; i <= n; i++) {
scanf("%lld", &c[i]);
c[i] += c[i - 1];
}
c[n + 1] = c[n] + N;
for (int i = 1; i <= n; i++)
printf("%d%c", slove(i, n + 1, c[i - 1] + h[i]), "\n "[i != n]);
return 0;
}