题解:P8343 [COCI2021-2022#6] Zemljište

题意

给定一个 r×s 的矩阵,每个点给定一个权值,要求求出一个子矩阵,其权值和为 w,使 |wa|+|wb| 最小。

分析

考虑枚举子矩阵。

首先预处理二维前缀和用于快速计算矩阵和。

可以暴力枚举左上角 (x1,y1) 和右下角 (x2,y2),这个做法是 O(n4) 的,显然一般情况下不能通过本题。


因为每个点的权值都大于 0,所以显然一个确定了 x1,x2,y1 矩阵的权值随 y2 的递增而单调递增。

考虑枚举 x1,x2,在确定 x1,x2 后用双指针移动 y1,y2 求出权值小于等于 max(a,b) 的最大权值的矩阵以及权值大于 max(a,b) 的最小权值的矩阵,用它们的权值更新答案。

这时时间复杂度下降至 O(n3),可以通过本题。

Code

#include<bits/stdc++.h>
using namespace std;
#define maxn 505
int64_t va[maxn][maxn];
#define query(x1, y1, x2, y2) (va[x2][y2]-va[x2][y1-1]-va[x1-1][y2]+va[x1-1][y1-1])
int main()
{
int n, m, a, b;
cin>>n>>m>>a>>b;
if(a>b) swap(a, b);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>va[i][j];
for(int i=1;i<=n+1;i++)
for(int j=1;j<=m+1;j++)
va[i][j]+=va[i-1][j]+va[i][j-1]-va[i-1][j-1];
int64_t ans=0x7fffffff;
for(int l=1;l<=n;l++)
for(int r=l;r<=n;r++)
for(int x=1, y=1;x<=m;x++)
{
if(y<x) y=x;
while(y+1<=m&&query(l, x, r, y+1)<=b) y++;
int64_t v=query(l, x, r, y);
ans=min(ans, abs(a-v)+abs(b-v));
v=query(l, x, r, y+1);
ans=min(ans, abs(a-v)+abs(b-v));
}
cout<<ans;
}

本文作者:redacted-area

本文链接:https://www.cnblogs.com/redacted-area/p/18429435

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Jimmy-LEEE  阅读(5)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起