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;
    }
  • 相关阅读:
    1451. Rearrange Words in a Sentence
    1450. Number of Students Doing Homework at a Given Time
    1452. People Whose List of Favorite Companies Is Not a Subset of Another List
    1447. Simplified Fractions
    1446. Consecutive Characters
    1448. Count Good Nodes in Binary Tree
    709. To Lower Case
    211. Add and Search Word
    918. Maximum Sum Circular Subarray
    lua 时间戳和时间互转
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/9506617.html
Copyright © 2011-2022 走看看