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;
    }
  • 相关阅读:
    javascript计算两个时间差
    angular 倒计时15 minute的方法封装
    一个页面多个倒计时的封装
    网站倒计时
    angularjs定时任务的设置与清除
    浏览器Event Loop 是个什么鬼
    一个图片测试的小网站:dummyimage.com
    在vscode 一行的末尾按下tab键 快速生成代码 很爽
    VSCODE 快捷键
    weex 在iOS 平台上的整合
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/10610189.html
Copyright © 2011-2022 走看看