zoukankan      html  css  js  c++  java
  • E. OpenStreetMap(单调队列)

      题意:给一个矩阵求a*b的子矩阵里最小值之和

      思路是开n个单调队列,然后当j>=b时,n个单调队列就会维护每一行每个长度为b的区间里的最小值,然后我们要从这n个单调队列的队头里,每a个取一个最小值(此最小值即为对应的a*b矩阵里的最小值),所以可以再用单调队列优化为O(N),不然直接暴力N*A会t。

    #include<bits/stdc++.h>
    using namespace std;
    #define ls rt<<1
    #define rs (rt<<1)+1
    #define ll long long
    #define fuck(x) cout<<#x<<"     "<<x<<endl;
    typedef  pair<int,int> pii;
    const int maxn=3e3+10;
    int d[4][2]={1,0,-1,0,0,1,0,-1};
    int q[maxn][maxn],h[maxn],t[maxn];
    pii qq[maxn];
    ll g[(int)1e7],mod,x,y,mp[maxn][maxn];
    int main()
    {
        int n,m,a,b;
        ll ans=0;
        scanf("%d%d%d%d%I64d%I64d%I64d%I64d",&n,&m,&a,&b,&(g[0]),&x,&y,&mod);
        for(int i=1;i<=n;i++) h[i]=1,t[i]=0;
        for(int i=1;i<=1e7-5;i++)
            g[i]=(g[i-1]*x+y)%mod;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                mp[i][j]=g[(i-1)*m+j-1];
        for(int j=1;j<=m;j++)
        {
            for(int i=1;i<=n;i++)
            {
                while(h[i]<=t[i]&&mp[i][q[i][t[i]]]>=mp[i][j]) t[i]--;
                q[i][++t[i]]=j;
                while(j-q[i][h[i]]>=b) h[i]++;
            }
            //cout<<endl;
            //for(int i=1;i<=n;i++) cout<<mp[i][q[i][h[i]]<<"    ";
            //cout<<endl;
            if(j>=b)
            {
                int head=1,tail=0;
                for (int i = 1; i <=n;i++)
                {
                   while(head<=tail&&mp[qq[tail].first][qq[tail].second]>=mp[i][q[i][h[i]]]) tail--;
                   qq[++tail]=make_pair(i,q[i][h[i]]);
                   while(i-qq[head].first>=a) head++;
                   if(i>=a)
                       ans+=mp[qq[head].first][qq[head].second];
                }
            }
    
        }
        printf("%I64d
    ",ans);
        return 0;
    }

    模板

    #include<bits/stdc++.h>//单调队列又称为滑动窗口
    using namespace std;
    #define ls rt<<1
    #define rs (rt<<1)+1
    #define ll long long
    #define fuck(x) cout<<#x<<"     "<<x<<endl;
    const int maxn=1e6+10;
    int d[4][2]={1,0,-1,0,0,1,0,-1};
    int a[maxn],q[maxn],ans1[maxn],ans2[maxn];
    
    
    
    int main()
    {
        int n,m,h,t;
        cin>>n>>m;
        for(int i=1;i<=n;i++) scanf("%d",&(a[i]));
        h=1,t=0;
        for(int i=1;i<=n;i++)//求m区间内最小值 以i为末尾的m区间  维护增队列
        {
            while(h<=t&&a[q[t]]>=a[i]) t--;//删去队尾的无用元素
            q[++t]=i;
            while(i-q[h]+1>=m+1) h++;//队头删去在所需区间外的元素
            if(i>=m)
                ans1[i-m+1]=a[q[h]];
        }
        h=1,t=0;
        for(int i=1;i<=n;i++)//求m区间内最大值   以i为末尾的m区间
        {
            while(h<=t&&a[q[t]]<=a[i]) t--;//删去队尾的无用元素
            q[++t]=i;
            while(i-q[h]+1>=m+1) h++;//队头删去在所需区间外的元素
            if(i>=m)
                ans2[i-m+1]=a[q[h]];
        }
        for(int i=1;i+m-1<=n;i++) printf("%d ",ans1[i]);
        cout<<endl;
        for(int i=1;i+m-1<=n;i++) printf("%d ",ans2[i]);
        cout<<endl;
        return 0;
    }
    
    
    
    
  • 相关阅读:
    封装成帧、帧定界、帧同步、透明传输(字符计数法、字符串的首尾填充法、零比特填充的首尾标志法、违规编码法)
    计算机网络之数据链路层的基本概念和功能概述
    物理层设备(中继器、集线器)
    计算机网络之传输介质(双绞线、同轴电缆、光纤、无线电缆、微波、激光、红外线)
    计算机网络之编码与调制
    0953. Verifying an Alien Dictionary (E)
    1704. Determine if String Halves Are Alike (E)
    1551. Minimum Operations to Make Array Equal (M)
    0775. Global and Local Inversions (M)
    0622. Design Circular Queue (M)
  • 原文地址:https://www.cnblogs.com/eason9906/p/11754741.html
Copyright © 2011-2022 走看看