[POI2006]ORK-Ploughinghttps://www.luogu.org/problemnew/show/P3444
题目描述
\(Byteasar\) 想耕种他那块矩形的田,他每次能耕种矩形的一边(上下左右都行), 在他每次耕完后,剩下的田也一定是矩形,每块小区域边长为 \(1\),耕地的长宽分 别为 \(m\) 和 \(n\),不幸的是 \(Byteasar\) 只有一匹老弱的马,从马开始耕地开始,只有当 它耕完了一边才会停下休息。但有些地会非常难耕以至于马会非常的累,因此 \(Byteasar\) 需要特别小心。当耕完了一边之后,马可以停下来休息恢复体力。每块 地耕种的难度不一,但是 \(Byteasar\) 都非常清楚。我们将地分成 \(m*n\) 块单位矩形 ——我们用坐标\((I,j)\)来定义它们。每块地都有一个整数 \(T[I,J]\),来定义\((I,j)\)的耕 种难度。所以每次马耕一边地时的难度就是所有它耕种的地的难度总和,对于这 匹虚弱的马而言,这个值不能超过他的体力值。\(Byteasar\) 想知道在马不死掉的情 况下最少需要耕多少次才能把地耕完。
输入格式:
第一行三个整数, \(K,M,N\)。 \(1<=k<=200 000 000\),\(1<=m,n<=2000\).其中 \(K\) 表示马的体力 值。 接下来 \(N\) 行每行 \(M\) 个整数表示难度值。\((0<=\)难度值\(<=10 000)\)
输出格式:
一个整数表示最少的耕种次数(保证马能耕完)。
输入样例:
12 6 4
6 0 4 8 0 5
0 4 5 4 6 0
0 5 6 5 6 0
5 4 0 0 5 4
输出样例:
8
贪心:
最少次数:\(min(n,m)\):直接只横切或只纵切切完
最多次数:\(n+m\):既横切又纵切
贪心策略:先优先横切,枚举切左边的次数\([1,m]\),尽可能少切右边
再优先纵切,枚举切上面的次数\([1,n]\),尽可能少切下边
所有次数取\(min\)即可
前缀和优化查询O(1)
存在无解的情况返回inf
#define RG register
#include<iostream>
#include<cstdio>
using namespace std;
const int N=2005;
inline int read()
{
RG int x=0,w=1;RG char ch=getchar();
while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)w=-1;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘)x=x*10+ch-‘0‘,ch=getchar();
return x*w;
}
int k,m,n,Ans=1e9;
int a[N][N],r[N][N],l[N][N];
inline int del1(int lim,int L,int R,int U,int D)
{
int Sum=0;
while(L<=R&&U<=D)
{
Sum++;
if(l[D][L]-l[U-1][L]<=k){L++;continue;}
if(l[D][R]-l[U-1][R]<=k){R--;continue;}
if((r[U][R]-r[U][L-1]<=k)&&(U<=lim)){U++;continue;}
if(r[D][R]-r[D][L-1]<=k)D--;
else return 1e9;
}
return Sum;
}
inline int del2(int lim,int L,int R,int U,int D)
{
int Sum=0;
while(L<=R&&U<=D)
{
Sum++;
if(r[U][R]-r[U][L-1]<=k){U++;continue;}
if(r[D][R]-r[D][L-1]<=k){D--;continue;}
if((l[D][L]-l[U-1][L]<=k)&&(L<=lim)){L++;continue;}
if(l[D][R]-l[U-1][R]<=k)R--;
else return 1e9;
}
return Sum;
}
int main()
{
k=read();
m=read();
n=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
a[i][j]=read();
r[i][j]=r[i][j-1]+a[i][j];
l[i][j]=l[i-1][j]+a[i][j];
}
for(int i=0;i<n;i++)Ans=min(Ans,del1(i,1,m,1,n));
for(int i=0;i<m;i++)Ans=min(Ans,del2(i,1,m,1,n));
printf("%d\n",Ans);
return 0;
}