• [APIO2009]采油区域


    题目描述

    Siruseri 政府决定将石油资源丰富的 Navalur 省的土地拍卖给私人承包商以 建立油井。被拍卖的整块土地为一个矩形区域,被划分为 M×N 个小块。 Siruseri 地质调查局有关于 Navalur 土地石油储量的估测数据。这些数据表示 为 M×N 个正整数,即对每一小块土地石油储量的估计值。 为了避免出现垄断,政府规定每一个承包商只能承包一个由 K×K 块相连的 土地构成的正方形区域。 AoE 石油联合公司由三个承包商组成,他们想选择三块互不相交的 K×K 的 区域使得总的收益最大。 例如,假设石油储量的估计值如下:

    说明

    数据保证 K≤M 且 K≤N 并且至少有三个 K×K 的互不相交的正方形区域。

    其 中 30%的输入数据,M, N≤ 12。所有的输入数据, M, N≤ 1500。每一小块土地的 石油储量的估计值是非负整数且≤ 500。

    题解

    弱化版的,可以爆搜即可。

    这个是增强版,要dp

    可以发现(很难想到),把这个原来的矩形选择3个k*k的正方形区域,

    如果我们把大矩形分成3块,总有一种切的方法,可以使得这3个选择的k*k的正方形区域,在每个小的块内都有一块。

    一共有6种方法:图片来源

    其中,每个正方形在一个小块内随便动。

    对于每一个1~6的情况,我们要枚举所有这种形态下的所有情况,计算出最大值,再取max

    直接暴力显然不可取。

    显然(难以)想到,每个块(除了5,6)都是和边界相交的。

    以下所有的i,j表示k*k矩形的右下角,姑且叫代表点

    所以,我们设a[i][j],b[i][j],c[i][j],d[i][j],表示,这个代表点在(i,j)左上、右上,左下,右下的所有情况中,k*k正方形最大的总和。

    对于a,b,c,d我们都可以以合理的方式递推得到。

    然后,再6次nm枚举6种形态的所有情况,取一个mx

    注意,(i,j)是代表点的坐标,所以我们循环的边界要注意。必须留出3个正方形的空间。

    画图举例想一想就很容易了。

    代码:(之后统计的编号对应在图中,都加了注释)

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=1505;
    int s[N][N],a[N][N],b[N][N],c[N][N],d[N][N];
    int ans,n,m,k;
    int main(){
        scanf("%d%d%d",&n,&m,&k);int t;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                scanf("%d",&t),s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+t;
        for(int i=n;i>=k;i--)
            for(int j=m;j>=k;j--)
                s[i][j]-=s[i-k][j]+s[i][j-k]-s[i-k][j-k];
        for(int i=k;i<=n;i++)
            for(int j=k;j<=m;j++)
                a[i][j]=max(s[i][j],max(a[i-1][j],a[i][j-1]));
        for(int i=k;i<=n;i++)
            for(int j=m;j>=k;j--)
                b[i][j]=max(s[i][j],max(b[i][j+1],b[i-1][j]));
        for(int i=n;i>=k;i--)
            for(int j=k;j<=m;j++)
                c[i][j]=max(s[i][j],max(c[i][j-1],c[i+1][j]));
        for(int i=n;i>=k;i--)
            for(int j=m;j>=k;j--)
                d[i][j]=max(s[i][j],max(d[i][j+1],d[i+1][j]));
        
        
    
      for(int i=k;i<=n-k;i++)//1
            for(int j=k;j<=m-k;j++)
                ans=max(ans,a[i][j]+b[i][j+k]+c[i+k][m]);
        for(int i=k+k;i<=n;i++)//2
            for(int j=k;j<=m-k;j++)
                 ans=max(ans,c[i][j]+d[i][j+k]+a[i-k][m]);
        for(int i=k+k;i<=n-k;i++)//6
            for(int j=k;j<=m;j++)
                ans=max(ans,s[i][j]+a[i-k][m]+c[i+k][m]);
        for(int i=k;i<=n-k;i++)//3
            for(int j=k;j<=m-k;j++)
                ans=max(ans,a[i][j]+c[i+k][j]+b[n][j+k]);
        for(int i=k;i<=n-k;i++)//4
            for(int j=k+k;j<=m;j++)
                ans=max(ans,a[n][j-k]+b[i][j]+d[i+k][j]);
        for(int i=k;i<=n-k;i++)//5
            for(int j=k+k;j<=m-k;j++)
                ans=max(ans,s[i][j]+a[n][j-k]+b[n][j+k]);
        printf("%d",ans);
        return 0;
    }    
  • 相关阅读:
    如何在dede栏目设置中添加自定义字段(dede二次开发-纯抄贴)
    dedecms内容页 上下篇 添加文章描述方法
    关于透明层----背景透明字不透明的效果
    什么是JavaScript闭包终极全解之一——基础概念
    phpcms v9中调用多栏目的方法--get标签(备实例)
    PHP识别电脑还是手机访问网站
    PHP中 post 与get的区别 详细说明
    js 处理数据里面的空格
    mysql中的unix_timestamp函数
    PHP中date函数月和日带0问题
  • 原文地址:https://www.cnblogs.com/Miracevin/p/9657177.html
Copyright © 2020-2023  润新知