[POI2006]ORK-Ploughing

[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
",Ans);
    return 0;
}
原文地址:https://www.cnblogs.com/sdzwyq/p/8468895.html