P5186 [COCI2009-2010#4] 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;
}