City Game
翻墙链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4076
无翻墙链接:https://vjudge.net/problem/UVA-1330
Solution
题目大意:给你一个只包含R和F的矩形,问你怎么选择一个子矩阵要求仅包含F,面积最大。(n,m<=1000)。
题解:此题看着可以暴搜,加上剪枝复杂度O(n*m*GG)。看看卡不卡了,总之很虚。
那么看看既然是子矩阵,那么就有一些特殊的性质,类似于暴搜的剪枝,如果上面一个元素不是F,那么矩阵就要中断。我们设U[i][j]代表,(i,j)所能向上拓展的最大高度,L[i][j]与R[i][j]分别代表左右,满足上界的最远距离坐标,那么这个就构成以个子矩阵了。可能会想,这个限制了L与R,会不会出现漏掉的情况呢?
答案是会!但不全会!例如:
RRRR
RRFR
RFFF
虽然在(3,3)的时候,答案是2(最优的答案是3啊!),但是一定会有(3,2)的时候来弥补,所以答案不会出错的。
那么我们就可以O(n*m)的转移方程了。如果这一位是R,那么U=0,否则U=上一层的U+1。L=max(上一层的L,这一层左边最近的一个R坐标+1)。注意是坐标,更好写。R类似,这样就可以统计出答案了。
1 #include<queue> 2 #include<cstdio> 3 #include<vector> 4 #include<cstring> 5 #include<iostream> 6 #include<algorithm> 7 #define RG register 8 #define LL long long 9 #define fre(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout); 10 using namespace std; 11 const int MAXN=1010; 12 int Case,n,m,ans; 13 int U[MAXN][MAXN],L[MAXN][MAXN],R[MAXN][MAXN]; 14 char s[MAXN][MAXN],g[10]; 15 int main() 16 { 17 scanf("%d",&Case); 18 while(Case--) 19 { 20 scanf("%d%d",&n,&m); 21 for(int i=1;i<=n;i++) 22 { 23 for(int j=1;j<=m;j++) 24 { 25 scanf("%s",g); 26 s[i][j]=g[0]; 27 } 28 } 29 ans=0; 30 for(int j=1;j<=m;j++) 31 U[1][j]=L[1][j]=R[1][j]=0; 32 for(int i=1;i<=n;i++) 33 { 34 int le=1,ri=m; 35 for(int j=1;j<=m;j++) 36 { 37 if(s[i][j]=='R') 38 le=j+1; 39 if(s[i][j]=='R') 40 { 41 U[i][j]=0; 42 L[i][j]=1; 43 } 44 else 45 { 46 U[i][j]=U[i-1][j]+1; 47 L[i][j]=max(L[i-1][j],le); 48 } 49 } 50 for(int j=m;j>=1;j--) 51 { 52 if(s[i][j]=='R') 53 ri=j-1; 54 if(s[i][j]=='R') 55 R[i][j]=m; 56 else 57 R[i][j]=min(R[i-1][j]==0?0x3f3f3f3f:R[i-1][j],ri); 58 } 59 for(int j=1;j<=m;j++) 60 ans=max(ans,3*U[i][j]*(R[i][j]-L[i][j]+1)); 61 } 62 printf("%d\n",ans); 63 } 64 return 0; 65 }