常见的优化技巧

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;
}
posted @ 2024-04-09 16:09  周哲宇Ghost  阅读(35)  评论(0)    收藏  举报