Loading

P5186 [COCI2009-2010#4] OGRADA 题解

题目链接:

P5186 OGRADA

大意:

给定 \(n\) 个宽度为 \(1\) 的矩形,求其中不能被宽度为 \(x\) 的扫描线覆盖的面积。

如上图,若 \(x=3\),则有 \(3\) 个方块无法被覆盖。

思路:

看到这种类型的题应该想到的都是单调数据结构,这道题看着像是单调栈,实际上是单调队列。

我们维护两个单调栈 \(q1,q2\),分别是单调递减和单调递增。首先用 \(q1\) 处理出长度为 \(x\) 的序列中的最小值。然后用 \(q2\) 处理出每个点 \(i(i>=x)\) 时能达到的最大矩形的高度。

对于每次刷漆,不妨在 \(q[i-1]\) 的基础上加上加上多余的。反过来想,便是 \(q[i]\) 减去与 \(q[i-1]\) 重合的部分即可,那么重合的部分的宽度一定为 \(x-1\),高度便为 \(q[i-1]\)。这样将面积累加到 \(ans\) ,最后用总面积减去 \(ans\) 即可求出子问题一。

对于子问题二,只需考虑有多少连续的相同高度的矩形,用宽度除去 \(x\) 向上取整即可。

代码

#include<bits/stdc++.h>
#define int long long
#define endl "\n"
template<typename P>
inline void read(P &x){
   	P res=0,f=1;
   	char ch=getchar();
   	while(ch<'0' || ch>'9'){
   		if(ch=='-') f=-1;
   		ch=getchar();
   	}
   	while(ch>='0' && ch<='9'){
   		res=res*10+ch-'0';
   		ch=getchar();
	}
	x=res*f;
}
using namespace std;
int T=1;
int n,k;
int a[1100010];
int q[1100010];
int b[1100010];
int S=0;
signed main(){
	read(n),read(k);
	for(int i=1;i<=n;++i) read(a[i]),S+=a[i];
	int l=1,r=0;
	int ans=0;
	for(int i=1;i<=n+k+1;++i){
		while(l<=r && i-q[l]>=k) l++;
		while(l<=r && a[i]<a[q[r]]) r--;
		q[++r]=i;
		if(i>=k) b[i]=a[q[l]];
	}
	l=1,r=0;
	memset(q,0,sizeof(q));
	memset(a,0,sizeof(a));
	for(int i=1;i<=n+k+1;++i){
		while(l<=r && i-q[l]>=k) l++;
		while(l<=r && b[i]>b[q[r]]) r--;
		q[++r]=i;
		if(i>=k) a[i]=b[q[l]];
		if(i>=k) ans+=k*a[i]-(k-1)*(a[i-1]);
	}
	int len=0;
	int ans1=0;
	for(int i=1;i<=n+k;++i){
		len++;
		if(a[i]!=a[i+1]){
			ans1+=ceil(len*1.0/k);
			len=0;
		}
	}
	cout<<S-ans<<endl;
	cout<<ans1-1<<endl;
	return 0;
}

posted @ 2024-07-25 15:02  God_Max_Me  阅读(7)  评论(0编辑  收藏  举报