[BZOJ]1810: [Ioi2005]gar 暴力

来源:互联网 发布:wpsoffice是什么软件 编辑:程序博客网 时间:2024/06/11 03:15

Description

Byteman拥有镇上最漂亮的花园。他在自己的花园里面种了N朵玫瑰花。夏天来了,所有的花都开的非常的漂亮。Byteman开始意识到自己没有能力看管自己花园里的所有的花,所以他决定雇佣两个园丁来帮助他。他想在花园中选择两块矩形的区域分别交给两个园丁看管。而且这两个矩形区域必须不能相交或者重叠,并且每一个区域要恰好包含K朵玫瑰花。 Byteman想要给这两块矩形区域的周围安上栅栏,但是他现在手头比较紧,所以他希望自己花的钱尽量的少。你的任务就是帮助Byteman选择两块矩形的区域,使得它们在满足条件的情况下周长和最小。 Byteman的花园有L米长,W米宽。花园被分成了L*W个大小相同(1*1)的方格。我们以平行与花园的两边建立起一个坐标系。所有的方格的坐标(x,y)满足1<=x<=L,1<=y<=W.每个方格内可能会有任意数目的玫瑰。 所选的矩形区域的两边必须跟花园的两边平行,并且矩形区域的四个角的坐标必须是整数。对于1<=L1<=L2<=L 并且 1<=W1<=W2<=W,一个矩形区域的四个角为(L1,W1),(L1,W2),(L2,W1)和(L2,W2): * 这个矩形内所包含的点的坐标(x,y)满足L1<=x<=L2并且W1<=y<=W2. * 这个矩形的周长是 2*(L2-11+1)+2*(W2-W1+1). 所选的两块矩形不能重叠或者相交。也就是它们不能有公共的方格。即使它们有公共的边,计算周长的时候也要分别计算。

题解:

遇到这种选矩形的题,如果选的矩形较少,可以考虑分类讨论,比如bzoj1177。这道题只要选两个矩形,那么它们的相对位置只有两种情况:
这里写图片描述
所以我们只需要预处理出上下左右的最小周长矩形就可以了。时间复杂度O(n3)

代码:

#include<bits/stdc++.h>using namespace std;const int Maxn=260;int read(){    int x=0,f=1;char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}    return x*f;}int r,c,n,m,a[Maxn][Maxn],sum[Maxn];int s1[Maxn],s2[Maxn],s3[Maxn],s4[Maxn];void work1(){    for(int i=1;i<=r;i++)//下面的行     {        for(int j=1;j<=c;j++)sum[j]=0;        for(int j=i;j;j--)//上面的行         {            for(int k=1;k<=c;k++)sum[k]+=a[j][k];//加上这一行             int p=1,s=0;            for(int k=1;k<=c;k++)//枚举右边列             {                s+=sum[k];                while(s>m&&p<k)s-=sum[p++];                while(!sum[p]&&p<k)p++;                if(s==m)s1[i]=min(s1[i],2*(i-j+1+k-p+1));            }        }    }    for(int i=r;i;i--)    {        for(int j=1;j<=c;j++)sum[j]=0;        for(int j=i;j<=r;j++)        {            for(int k=1;k<=c;k++)sum[k]+=a[j][k];            int p=1,s=0;            for(int k=1;k<=c;k++)            {                s+=sum[k];                while(s>m&&p<k)s-=sum[p++];                while(!sum[p]&&p<k)p++;                if(s==m)s2[i]=min(s2[i],2*(j-i+1+k-p+1));            }        }    }}void work2(){    for(int i=1;i<=c;i++)    {        for(int j=1;j<=r;j++)sum[j]=0;        for(int j=i;j;j--)        {            for(int k=1;k<=r;k++)sum[k]+=a[k][j];            int p=1,s=0;            for(int k=1;k<=r;k++)            {                s+=sum[k];                while(s>m&&p<k)s-=sum[p++];                while(!sum[p]&&p<k)p++;                if(s==m)s3[i]=min(s3[i],2*(i-j+1+k-p+1));            }        }    }    for(int i=c;i;i--)    {        for(int j=1;j<=r;j++)sum[j]=0;        for(int j=i;j<=c;j++)        {            for(int k=1;k<=r;k++)sum[k]+=a[k][j];            int p=1,s=0;            for(int k=1;k<=r;k++)            {                s+=sum[k];                while(s>m&&p<k)s-=sum[p++];                while(!sum[p]&&p<k)p++;                if(s==m)s4[i]=min(s4[i],2*(j-i+1+k-p+1));            }        }    }}int main(){    memset(s1,63,sizeof(s1));    memset(s2,63,sizeof(s2));    memset(s3,63,sizeof(s3));    memset(s4,63,sizeof(s4));    r=read();c=read();n=read();m=read();    for(int i=1;i<=n;i++)a[read()][read()]++;    work1();work2();    int ans=1061109567;    for(int i=1;i<r;i++)    for(int j=i+1;j<=r;j++)    ans=min(ans,s1[i]+s2[j]);    for(int i=1;i<c;i++)    for(int j=i+1;j<=c;j++)    ans=min(ans,s3[i]+s4[j]);    if(ans==1061109567)puts("NO");    else printf("%d",ans);}