SRM552 Div1Medium FoxAndFlowerShopDivOne

来源:互联网 发布:屏蔽按键软件 编辑:程序博客网 时间:2024/06/08 17:36

【分析】
题目核心的意思就是找两个不相交的矩形并维护矩形中的信息。
然而朴素的暴力枚举当然是过不了的(n≤30)
因为做过求面积这类的问题,所以就想到了扫描线
而且这个扫描线既要枚举垂直于x轴的,也要枚举垂直于y轴的。
但是单纯的扫描线并不能解决问题。我们要满足区域内百合花的数量与牵牛花的数量之差的绝对值不超过K的情况下再去寻找数量最大的。
我们将百合花定义为1,牵牛花定义为-1。
我们可以用dp[i][j]表示对于x=i这条扫描线左边的花之和为j的花的数量最多。
rdp[i][j]表示右边。
这样就可以转移了。
y=i的情况同理。
注意:既然有-1,那么我们一定要将j加上一个数,防止他爆炸。但是这么做会有很多的小细节。希望大家要慢慢调。

【代码】

#include<cstdio>#include<cstring>#include<cctype>#include<algorithm>#include<iostream>#include<string>#include<vector> using namespace std;#define N 35#define M 2000#define oo 1e9char A[N][N];int ans=-oo,n,m,lim;int B[N][N],C[N][N];int dp[N][M],rdp[N][M];void chk(int &x,int y){    if(x<y)x=y;}int sum(int x1,int y1,int x2,int y2) {    return B[x2][y2]+B[x1-1][y1-1]-B[x2][y1-1]-B[x1-1][y2];}int calc(int x1,int y1,int x2,int y2) {    return C[x2][y2]+C[x1-1][y1-1]-C[x2][y1-1]-C[x1-1][y2];}int main(){    scanf("%d %d %d",&n,&m,&lim);    for(int i=0;i<n;i++)scanf("%s",A[i]);    for(int i=1;i<=n;i++){        for(int j=1;j<=m;j++){            if(A[i-1][j-1]=='L')B[i][j]=1;            if(A[i-1][j-1]=='P')B[i][j]=-1;            if(B[i][j])C[i][j]=1;            B[i][j]+=B[i-1][j]+B[i][j-1]-B[i-1][j-1];            C[i][j]+=C[i-1][j]+C[i][j-1]-C[i-1][j-1];        }    }    for(int i=0;i<=n+1;i++)for(int j=0;j<=1800;j++)dp[i][j]=rdp[i][j]=-oo;    for(int i=1;i<=n;i++){        for(int j=1;j<=m;j++){            for(int x=1;x<=i;x++){                for(int y=1;y<=j;y++){                    int t=sum(x,y,i,j)+900;                    chk(dp[i][t],calc(x,y,i,j));                 }            }        }        for(int j=0;j<=1800;j++)chk(dp[i][j],dp[i-1][j]);    }    for(int i=n;i>=1;i--){        for(int j=1;j<=m;j++){            for(int x=i;x<=n;x++){                for(int y=j;y<=m;y++){                    int t=sum(i,j,x,y)+900;                    chk(rdp[i][t],calc(i,j,x,y));                 }            }        }        for(int j=0;j<=1800;j++)chk(rdp[i][j],rdp[i+1][j]);    }    for(int i=1;i<n;i++){        for(int j=0;j<=1800;j++){            int l=max(0,1800-j-lim);            int r=min(1800,1800+lim-j);            for(int k=l;k<=r;k++){                if(j+k-1800<-k||j+k-1800>k)continue;                chk(ans,dp[i][j]+rdp[i+1][k]);            }        }    }    for(int i=0;i<=m+1;i++){        for(int j=0;j<=1800;j++)dp[i][j]=rdp[i][j]=-oo;    }    for(int i=1;i<=m;i++){        for(int j=1;j<=n;j++){            for(int x=1;x<=j;x++){                for(int y=1;y<=i;y++){                    int t=sum(x,y,j,i)+900;                    chk(dp[i][t],calc(x,y,j,i));                 }            }        }        for(int j=0;j<=1800;j++)chk(dp[i][j],dp[i-1][j]);    }    for(int i=m;i>=1;i--){        for(int j=1;j<=n;j++){            for(int x=j;x<=n;x++){                for(int y=i;y<=m;y++){                    int t=sum(j,i,x,y)+900;                    chk(rdp[i][t],calc(j,i,x,y));                 }            }        }        for(int j=0;j<=1800;j++)chk(rdp[i][j],rdp[i+1][j]);    }    for(int i=1;i<m;i++){        for(int j=0;j<=1800;j++){            int l=max(0,1800-j-lim);            int r=min(1800,1800+lim-j);            for(int k=l;k<=r;k++){                if(j+k-1800<-k||j+k-1800>k)continue;                chk(ans,dp[i][j]+rdp[i+1][k]);            }        }    }    if(ans<0)ans=-1;    printf("%d\n",ans);    return 0;}
0 0