题解:P15197 [SWERC 2018] Blurred Pictures
MengTian1120 · · 题解
前言
本篇题解的解题方法为:单调队列,二分答案。
题目大意
觉得题目难理解的,可以试试结合样例理解。
:::info[题目]
Damon 喜欢为他旅行中所到之处拍摄照片,并将它们装入相框。他所有的照片都是
重要提示
- 在输入图片中,每行和每列至少有一个非模糊像素。
- 在任何连续两行中,至少有两列有非模糊像素。 :::
题目其实就是:
给
找出在这个图像中最大的清晰正方形边长。
注意,正方形的边必须与图片的边平行!
解题思路
因为这道题具有单调性,所以我们可以用二分答案。
如果边长
那么边长
如果边长
那么边长
写一个 bool check(int k) 函数,检查边长为
在 check(k) 中,我们需要对每个长度为 k 的连续行窗口,快速求出:
- 窗口内的最大值。
- 窗口内的最小值。
如果每次重新遍历窗口内所有元素,复杂度是 check(k) 就会变成
单调队列可以在
不会的可以去看看 P1886 【模板】单调队列 / 滑动窗口,这道题是单调队列的模板题。
时间复杂度:
- 二分答案:
O(\log N) 。 - 每次
check(k):O(N) 。 - 总复杂度:
O(N \log N) 。
对于数据范围
代码实现
我们可以使用 STL 中的 deque 来写单调队列,节省空间。
在主函数进行二分。
AC 代码
#include <bits/stdc++.h>
using namespace std;
int n,a[100005],b[100005];
bool check(int k){
deque <int> q1,q2;
for(int i=1;i<=n;i++){
while(!q1.empty() && a[q1.back()]<=a[i]) q1.pop_back();
q1.push_back(i);
while (!q2.empty() && b[q2.back()]>=b[i]) q2.pop_back();
q2.push_back(i);
if(i>=k){
if(q1.front()==i-k) q1.pop_front();
if(q2.front()==i-k) q2.pop_front();
if(a[q1.front()]<=b[q2.front()]-k+1) return true;
}
}
return false;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i]>>b[i];
int l=1,r=n,ans=1;
while(l<=r){
int mid=(r+l)/2;
if(check(mid)) ans=mid,l=mid+1;
else r=mid-1;
}
cout<<ans;
return 0;
}
record
后记
这是本蒟蒻的第
给个赞再走呗!