常见的优化技巧
P1638 逛画展
滑动窗口优化时间复杂度,此处求解的是窗口长度的最小值。r先右移到符合count=m的要求。后l在满足题意的情况下右移,并不断更新最短区间长度。
代码如下:
#include <iostream>
#include <cstring>
#define MAXN 10010
using namespace std;
int main() {
int n,m;
cin>>n>>m;
int rec[n+1],temp[m+1];
memset(rec,0,sizeof(rec));
memset(temp,0,sizeof(temp));
for (int i=1;i<=n;i++) cin>>rec[i];
int l=1,r=1,count=0,a=0,b=n;
while(l<=r&&r<=n){
if (temp[rec[r]]==0) count++;
temp[rec[r]]++;
if (count==m){
while (true){
if (temp[rec[l]]==1) {
break;
}
temp[rec[l]]--;
l++;
}
if ((b-a)>(r-l)){
a=l;
b=r;
}
}
r++;
}
cout<<a<<' '<<b<<endl;
}
UVA11572 唯一的雪花
滑动窗口优化时间复杂度,此处求解的是窗口长度的最大值。r右移探索可能结果,更新ans。当repeat=1时,l右移进行去重。
代码如下:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn=1e6;
int main() {
int t;
cin>>t;
while(t--){
int n,a[maxn],ans=0,mp[maxn];
memset(mp,0,sizeof(mp));
cin>>n;
for (int i=1;i<=n;i++) cin>>a[i];
int l=1,r=1,repeat=0;
while (l<=r&&r<=n){
if (repeat==0){
mp[a[r]]++;
if (mp[a[r]]==2) repeat=1;
else ans=max(ans,r-l+1);//不同于求min窗口,此处在r右移时更新ans
r++;
}
else {
mp[a[l]]--;
if (mp[a[l]]==1) repeat=0;
l++;
}
}
cout<<ans<<endl;
}
}
P2032 扫描
经典单调队列问题,固定窗口滑动。每次右移之后的“新成员”都会干掉能力比他弱的“老东西”,同时注意定期删除年龄超限的“老成员”。每一次队列中的元素单调递减,取队首就是当前窗口内元素的最大值。
PS:记一下模版void insert(int pos_);int query(int pos_);
代码如下:
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
const int maxn=1e6;
int n,m,a[maxn];
int head,tail,q[maxn];
vector<pair<int,int>> interval;
void clear(){
head=1;
tail=0;
}
void insert(int pos_){
while (head<=tail&&a[pos_]>=a[q[tail]]) tail--;
q[++tail]=pos_;
}
int query(int pos_){
while(head<=tail&&q[head]+m-1<pos_) head++;
return q[head];
}
int main() {
cin>>n>>m;
int ans=-maxn;
for (int i=1;i<=n;i++) cin>>a[i];
for (int i=1;i<=n;i++){
insert(i);//插入的是队尾元素i
if (i>=m){
int rec=query(i);//当队尾是i时,该队列队首,也就是当前滑动窗口的min
cout<<a[rec]<<endl;
}
}
return 0;
}

浙公网安备 33010602011771号