题意都是求最大子矩阵和。
自己用O(n^3)的算法,直接给我无情的TLE (T..><..T)
随后看到了这个位置迭代算法。
left[i] 表示在第i号元素的左边从left[i]至i中, elem[j] >= elem[i] ( left[i]<=j<=i) ;这样就可以立即知道它左边最大合适的宽度,而高度就是elem[i],所以左边的面积就是elem[i]*(i-left[i]+1)。
同理可得,用right[i]表示在第i号元素的右边从i->>>right[i] 中,elem[j]>=elem[i] ( i<=j<=right[i]),所以右边的面积就是elem[i]*(right[i]-i+1).
但是上面包含了两个elme[i],就是第i号元素取了两次。
总面积就为:area[i]=elem[i] *(right[i]-left[i]+1).
最后的方程就变成了Maxelem=max(area[j]) ) ( 1<=j<=n).
至于left,与right的求法如以下代码:它们的顺序各有不同,为什么?自己思考。
for(i=1;i<=m;i++) while(num[left[i]-1]>=num[i]) left[i]=left[left[i]-1]; for(i=m;i>=1;i--) while(num[right[i]+1]>=num[i]) right[i]=right[right[i]+1];
hdu1506(hdu1505是它的加强版,在下面会讲)代码如下:
#include<cstdio> #define M 100010 #define FLAG -1 #define Max(a,b) (a)>(b)?(a):(b) __int64 elem[M]; int main(){ int n,i,right[M],left[M]; while(scanf("%d",&n) && n ){ for(i=1;i<=n;i++){ scanf("%I64d",&elem[i]); right[i]=left[i]=i; } elem[0] = elem[n+1] = FLAG; for(i=1;i<=n;i++) while(elem[left[i]-1]>=elem[i]) left[i]=left[left[i]-1]; for(i=n;i>=1;i--) while(elem[right[i]+1]>=elem[i]) right[i]=right[right[i]+1]; __int64 maxMatrix=0; for(i=1;i<=n;i++) maxMatrix=Max(maxMatrix,(__int64)(right[i]-left[i]+1)*elem[i]); printf("%I64d\n",maxMatrix); } return 0; }
然后采用上题的方式求解。
#include<iostream> #include<cstring> #include<cstdio> using namespace std; #define M 1005 #define MAX(a,b) (a)>(b)?(a):(b) char s[M*3]; int n,m,T,num[M],Max; void dp(){ int left[M],right[M],i; for(i=1;i<=m;i++) left[i]=right[i]=i; for(i=1;i<=m;i++) while(num[left[i]-1]>=num[i]) left[i]=left[left[i]-1]; for(i=m;i>=1;i--) while(num[right[i]+1]>=num[i]) right[i]=right[right[i]+1]; for(i=1;i<=m;i++) Max=MAX((right[i]-left[i]+1)*num[i],Max); } void init(){ scanf("%d %d",&n,&m); memset(num,0,sizeof(num)); num[0]=num[m+1]=-1; Max=0; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ scanf("%s",s); s[0]=='F'?num[j]++:num[j]=0; } dp(); } } int main(){ scanf("%d",&T); while(T--){ init(); cout<<3*Max<<endl; } return 0; }