zoukankan      html  css  js  c++  java
  • [HAOI2007]理想的正方形

    传送门

    DP
    其实主要是单调队列..
    数据最大为一千,考虑O(n^2)的做法
    在a*b的矩形中找出n^n的正方形再怎么样至少也要把a和b分别枚举吧。
    必须考虑O(1)处理单个正方形最大最小值。
    容易发现正方形大小不变为n,如果只看一行,就是滑动窗口,那么处理单个正方形最大最小值时间复杂度为O(n);
    仔细思考后(没错不管是什么题目仔细思考后就一定能想出正解..)发现如果把单调队列更新的值存起来为mxa[i][j],mxa[i][j]表示第i行以第j列为结尾的数列的最大值.
    则要求mxb[i][j](mxb[i][j]表示以i,j为右下角的正方形的最大值)就只要对mxa竖着跑b遍单调队列就好了..
    正解出来了,但要注意i,j,的范围..

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    using namespace std;
    int n,m,k;
    int a[1007][1007];
    int posx[1007],posi[1007];
    int mxa[1007][1007],mia[1007][1007];
    int mxb[1007][1007],mib[1007][1007];
    int main()
    {
        cin>>n>>m>>k;
        for(int i=1;i<=n;i++)
        {
            int heax=1,lasx=0,heai=1,lasi=0;
            for(int j=1;j<=m;j++)
            {
                scanf("%d",&a[i][j]);
                while(heax<=lasx&&a[i][j]>=a[i][posx[lasx]]) lasx--;
                while(heai<=lasi&&a[i][j]<=a[i][posi[lasi]]) lasi--;
                while(heax<=lasx&&j-posx[heax]>=k) heax++;
                while(heai<=lasi&&j-posi[heai]>=k) heai++;
                posx[++lasx]=j; posi[++lasi]=j;
                if(j>=k) mxa[i][j-k+1]=a[i][posx[heax]],mia[i][j-k+1]=a[i][posi[heai]];
            }
        }
        memset(posx,0,sizeof(posx));
        memset(posi,0,sizeof(posi));
        for(int j=1;j<=m-k+1;j++)
        {
            int heax=1,lasx=0,heai=1,lasi=0;
            for(int i=1;i<=n;i++)
            {
                while(heax<=lasx&&mxa[i][j]>=mxa[posx[lasx]][j]) lasx--;
                while(heai<=lasi&&mia[i][j]<=mia[posi[lasi]][j]) lasi--;
                while(heax<=lasx&&i-posx[heax]>=k) heax++;
                while(heai<=lasi&&i-posi[heai]>=k) heai++;
                posx[++lasx]=i; posi[++lasi]=i;
                if(i>=k) mxb[i-k+1][j]=mxa[posx[heax]][j],mib[i-k+1][j]=mia[posi[heai]][j];
            }
        }
        int ans=2147483647;
        for(int i=1;i<=n-k+1;i++)
            for(int j=1;j<=m-k+1;j++)
                ans=min(ans,mxb[i][j]-mib[i][j]);
        cout<<ans;
        return 0;
    }
  • 相关阅读:
    2017-9-8-Linux下VNC server开启&图形界面显示
    2017-9-8-RaspberryPi安装过程
    2017-9-7-Linux Mint TFTP服务安装开启
    2017-9-7-第一篇博客
    面试回答优缺点问题
    多层板的层叠和压合结构
    磁珠和电感
    关于TVS、ESD、稳压二极管、压敏电阻
    STM8硬件设计注意事项
    根据电路板画出电路原理图的方法
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/9506617.html
Copyright © 2011-2022 走看看