zoukankan      html  css  js  c++  java
  • P2219 [HAOI2007]修筑绿化带

    传送门

    首先显然我们可以维护一个二维前缀和 $O(1)$ 求出任意一个矩形的值

    考虑枚举大矩形的左上角,并维护当前矩形中,小矩形的最小值

    放一个图:

    维护小矩形最小值先考虑暴力怎么搞

    同样考虑枚举左上角,那么大概枚举过程可以长成这个样子:

    发现可以先预处理出同一排竖下来的小矩形最小值,显然这个可以直接单调队列维护

    然后对于同一横排的大矩形的小矩形最小值就可以用预处理出的竖的一段小矩形最小值搞单调队列同样维护

    然后是一些边界的细节问题了,注意大矩形必须完全包含小矩形,边界不能重叠!

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<vector>
    using namespace std;
    typedef long long ll;
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    const int N=2e3+7;
    int n,m,A,B,C,D,ans;
    int sum[N][N],E[N][N],F[N][N];
    int G[N][N];
    int Q[N];
    inline int SUM(int xa,int ya,int xb,int yb) { return sum[xb][yb]-sum[xa-1][yb]-sum[xb][ya-1]+sum[xa-1][ya-1]; }
    //求以(xa,ya)为左上角,(xb,yb)为右下角的矩形的值
    int main()
    {
        n=read(),m=read(),A=read(),B=read(),C=read(),D=read();
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++) sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+read();
        for(int i=1;i+A-1<=n;i++)
            for(int j=1;j+B-1<=m;j++) E[i][j]=SUM(i,j,i+A-1,j+B-1);//求大矩形的值
        for(int i=1;i+C-1<=n;i++)
            for(int j=1;j+D-1<=m;j++) F[i][j]=SUM(i,j,i+C-1,j+D-1);//求小矩形的值
        int l,r,p;
        for(int j=2;j+D-1<m;j++)//求竖的一段小矩形的最小值
        {
            l=1,r=0,p=2;
            for(int i=1;i+A-1<=n;i++)
            {
                while(Q[l]<=i&&l<=r) l++;
                while(p<i+A-C)
                {
                    while(F[Q[r]][j]>=F[p][j]&&l<=r) r--;
                    Q[++r]=p; p++;
                }
                G[i][j]=F[Q[l]][j];
            }
        }
        for(int i=1;i+A-1<=n;i++)
        {
            l=1,r=0,p=2;
            for(int j=1;j+B-1<=m;j++)
            {
                while(Q[l]<=j&&l<=r) l++;
                while(p<j+B-D)
                {
                    while(G[i][Q[r]]>=G[i][p]&&l<=r) r--;
                    Q[++r]=p; p++;
                }
                ans=max(ans,E[i][j]-G[i][Q[l]]);
            }
        }
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    CAN总线布线规范
    使用make_ext4fs时报错,No such file or directory
    安装arm-2009q3交叉编译器后,执行No such file....
    Busybox下make menconfig报错处理!
    解决Markdown转为PDF后,尖括号不能正确显示问题。
    开发板与PC直连 交叉、直连网线做法
    BusyBox tftp使用
    STM32的flash数据页转存过程分析!
    c语言中log函数的使用!
    POJ 3667 Hotel
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/10610189.html
Copyright © 2011-2022 走看看