题目

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

1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1
1 8 8 8 8 8 1 1 1
1 8 8 8 8 8 1 1 1
1 8 8 8 8 8 1 1 1
1 1 1 1 8 8 8 1 1
1 1 1 1 1 1 8 8 8
1 1 1 1 1 1 9 9 9
1 1 1 1 1 1 9 9 9
如果 K = 2, AoE 公司可以承包的区域的石油储量总和为 100, 如果 K = 3, AoE 公司可以承包的区域的石油储量总和为 208。 AoE 公司雇佣你来写一个程序,帮助计算出他们可以承包的区域的石油储量 之和的最大值。

输入格式
输入第一行包含三个整数 M, N, K,其中 M 和 N 是矩形区域的行数和列数, K 是每一个承包商承包的正方形的大小(边长的块数)。接下来 M 行,每行有 N 个正整数表示这一行每一小块土地的石油储量的估计值。

输出格式
输出只包含一个正整数,表示 AoE 公司可以承包的区域的石油储量之和的 最大值。

输入输出样例
输入 #1复制
9 9 3
1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1
1 8 8 8 8 8 1 1 1
1 8 8 8 8 8 1 1 1
1 8 8 8 8 8 1 1 1
1 1 1 1 8 8 8 1 1
1 1 1 1 1 1 8 8 8
1 1 1 1 1 1 9 9 9
1 1 1 1 1 1 9 9 9
输出 #1复制
208
说明/提示
数据保证 K≤M 且 K≤N 并且至少有三个 K×K 的互不相交的正方形区域。

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

思路

按照分类讨论的思想,我们把一个矩形劈成三份有六种方法,之后我们去维护:

靠左上,右上,左下,右下的的矩形区域中,选一个正方形的最大ans是多少。

然后维护,linei,j为第i行到第j行选一个正方形的最大ansans,列上同理

之后我们就可以枚举六种分割情况计算答案了

代码

int n,m,k;
int sum[1510][1510],a[1510][1510];
int lu[N][N],ru[N][N],ld[N][N],rd[N][N],col[N][N],line[N][N];
int main(){
    n = read(),m = read(),k = read();
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            a[i][j] = read(),
            sum[i][j] = sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
    for(int i=1;i<=n;i++,printf("\n"))
        for(int j=1;j<=m;j++)
            printf("%d ",sum[i][j]);
    for(int i=k;i<=n;i++)
        for(int j=k;j<=m;j++)
            lu[i][j] = max(max(lu[i-1][j],lu[i][j-1]),sum[i][j]-sum[i-k][j]-sum[i][j-k]+sum[i-k][j-k]);
    for(int i=k;i<=n;i++)
        for(int j=m-k+1;j>0;j--)
            ru[i][j] = max(max(ru[i-1][j],ru[i][j+1]),sum[i][j+k-1]-sum[i][j-1]-sum[i-k][j+k-1]+sum[i-k][j-1]);
    for(int i=n-k+1;i>0;i--)
        for(int j=1;j<=m;j++)    
            ld[i][j] = max(max(ld[i+1][j],ld[i][j-1]),sum[i+k-1][j]-sum[i-1][j]-sum[i+k-1][j-k]+sum[i-1][j-k]);
    for(int i=n-k+1;i>0;i--)
        for(int j=m-k+1;j>0;j--)
            rd[i][j] = max(max(rd[i+1][j],rd[i][j+1]),sum[i+k-1][j+k-1]-sum[i+k-1][j-1]-sum[i-1][j+k-1]+sum[i-1][j-1]);
    for(int i=k;i<=n;i++)
        for(int j=k;j<=m;j++)
            line[i-k+1][i] = max(line[i-k+1][i],sum[i][j]-sum[i-k][j]-sum[i][j-k]+sum[i-k][j-k]);
    for(int len=k+1;len<=n-k;len++)
        for(int j=len;j<=n;j++)
            line[j-len+1][j] = max(line[j-len+1][j],max(line[j-len+2][j],line[j-len+1][j-1]));
    for(int i=k;i<=m;i++)
        for(int j=k;j<=n;j++)
            col[i-k+1][i] = max(col[i-k+1][i],sum[j][i]-sum[j-k][i]-sum[j][i-k]+sum[j-k][i-k]);
    for(int len=k+1;len<=n-k;len++)
        for(int j=len;j<=m;j++)
            col[j-len+1][j] = max(col[j-len+1][j],max(col[j-len+2][j],col[j-len+1][j-1]));
    int ans = 0;
    for(int i=k;i<=n-k+1;i++)
        for(int j=k;j<=m-k+1;j++){
            ans = max(ans,lu[i][j]+ld[i+1][j]+ru[n][j+1]);
            ans = max(ans,lu[n][j]+ru[i][j+1]+rd[i+1][j+1]);
            ans = max(ans,lu[i][m]+rd[i+1][j]+ld[i+1][j-1]);
            ans = max(ans,lu[i][j]+ru[i][j+1]+ld[i+1][m]);
        }
    for(int i=k;i<=n-2*k+1;i++)
        for(int j=i+k;j<=n-k+1;j++)
            ans = max(ans,line[1][i]+line[i+1][j]+line[j+1][n]);
    for(int i=k;i<=m-2*k;i++)
        for(int j=i+k;j<=m-k+1;j++)
            ans = max(ans,col[1][i]+col[i+1][j]+col[j+1][n]);
    printf("%d\n",ans);
    return 0;                
}