• 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;
    }
    
    
    
    
  • 相关阅读:
    HttpContext请求上下文对象
    HttpRuntime类
    HttpServerUtility类
    【POJ3614】Sunscreen
    【poj1995】Raising Modulo Numbers
    【poj3263】Tallest Cow(差分数组)
    【HNOI2003】【BZOJ1218】激光炸弹
    STL入门基础【OI缩水版】
    【TJOI2016】【bzoj4552】排序(二分答案+线段树01排序)
    【POJ3784】Running Median(中位数,对顶堆)
  • 原文地址:https://www.cnblogs.com/eason9906/p/11754740.html
Copyright © 2020-2023  润新知