WYT的刷子 题解

分析

  • 如果某一个栅栏能被刷完,他向左和向右延伸的宽度(包括自己)之和应该不小于刷子的宽度 \(M\),因此,我们可以先处理一下每个栅栏向左向右延伸的宽度。
    两个 \(O(n)\) 单调栈搞一下
// 找出以第i个栅栏高度为基准向左向右延伸的长度
// 维护单调递增的栈,这个是向右的
head = 0, tail = -1;
for (int i = 1; i <= n + 1; ++i) { // 多一个元素,可以让所有的都出栈
	while (head <= tail && h[i] < h[que[tail]]) {
		r[que[tail]] = i - que[tail];
		--tail;
	}
	que[++tail] = i;
}
  • 得到了延伸的宽度之后,我们也就可以判断每个栅栏是否能被完整的粉刷,可以先给每个栅栏标记一下,即如果延伸的宽度不小于 \(M\),则标记为能刷完,否则标记为刷不完
// 统计哪些不能刷完,就是左右延伸的宽度小于m
for (int i = 1; i <= n; ++i) {
	if (l[i] + r[i] - 1 >= m) flag[i] = true; // 可以刷完
}
  • 因为要求最少剩下的方块数量,下一步我们就可以求一下每个栅栏还剩多少不能刷,递推处理一下每个栅栏能被刷的最大高度。
    我们先从左往右考虑一下,如果第i个栅栏能被刷完,那么最大高度就是它本身的高度;如果不能,则它的高度一定比它左边的栅栏能刷的最大高度要大(如果不成立,那么它完全可以接在它左边的栅栏上,把自己刷完),因此它能刷到的最大高度就是它左边的栅栏能刷到的最大高度。
    然后还要从右边处理一下,有可能对于每一个栅栏,右边过来可能刷的更高,所以需要求一下最值。
    既然有了每个栅栏能刷的最大高度,那么用每个栅栏的高度之和减去所有能刷的最大高度就是剩余的面积。
// 统计每个楼能刷的最大高度,左边跟我一起画个龙
for (int i = 1; i <= n; ++i) {
	if (flag[i]) mh[i] = h[i];
	else { // 如果i刷不完,那么它左边能刷到的高度一定小于i的高度,否则肯定能刷完i
		mh[i] = mh[i-1];
	}
}
// 右边再画一道彩虹
for (int i = n; i > 0; --i) {
	if (!flag[i]) { // 如果i刷不完,那么它左边能刷到的高度一定小于i的高度,否则肯定能刷完i
		mh[i] = max(mh[i], mh[i+1]);
	}
	sum -= mh[i];
}
  • 要求刷的次数,因为每个栅栏都要刷到最高,所以贪心刷就可以了。如果几个连续的栅栏刷的最大高度相同,那么就一起刷,宽度除以 \(M\) 就是次数。如果相邻两个刷的高度不一样,那么从此处断开重新刷就可以了。
// 刷的次数贪心搞,因为每个都要刷到最高,每次都贪心刷最宽就行了
int k = 2, ans = 0;
while (k <= n + 1) { // 多循环一次,保证所有的都在一个循环里刷完
	int cnt = 1;
	while (k <= n + 1 && mh[k] == mh[k-1]) {
		++cnt;
		++k;
	}
	ans += cnt / m;
	if (cnt % m) ++ans;
	++k;
}
posted @ 2020-07-01 11:55  狂飙霹雳虎  阅读(268)  评论(0编辑  收藏  举报