1505,1506一类题,1505套用1506即可
就像最大子阵和与最大连续子和的关系
回顾最大连续子序列
状态方程:sum[i]=max(sum[i-1]+a[i],a[i]);最后从头到尾扫一边
Sum[i]为以i结尾的最大连续子和
也可以写成:
Max=a[0];
Current=0;
for(i=0;i<n;i++)
{
if(Current<0)
Current=a[i];
else
Current+=a[i];
if(Current>Max)
Max=Current;
}
最大子矩阵记录方式做一些处理就可以直接用最大连续子序列的做法
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
scanf("%d",&t);
a[i][j]=a[i-1][j]+t;
}
a[i][j]表示第1行到第i行第j列的和…草,反正我能想明白,不解释。
对每一行都可以用最大子序列之和。
回到这个题,其实效率高在left right 数组
Left[i]=t,表示v[t],v[t+1]…v[i]均满足>=v[i],下面的循环就能理解了
以及从中间往两边搜的思想
//hdu 1506 #include<cstdio> #include<cstring> #include<cstdlib> using namespace std; #define N 100005 long long max,ae,a[N],left[N],right[N]; int i,n,k; int main() { while(scanf("%d",&n)!=EOF) { if(!n)break; max=0; for(i=0;i<n;i++) { scanf("%I64d",&a[i]); } left[0]=0; right[n-1]=n-1; for(i=1;i<n;i++) { k=i; while(k>=1&&a[i]<=a[k-1])k=left[k-1]; left[i]=k; } for(i=n-2;i>=0;i--) { k=i; while(k<=n-2&&a[i]<=a[k+1])k=right[k+1]; right[i]=k; } for(i=0;i<n;i++) { ae=(right[i]-left[i]+1)*a[i]; max=max>ae?max:ae; } printf("%I64d\n",max); } return 0; }
//hdu 1505 #include<cstdio> #include<cstring> #include<cstdlib> using namespace std; #define N 1005 int map[N][N]; long long left[N],right[N],a[N],ae,max;/*left[i]=j存的是从a[j]到a[i]都满足>=a[i], 故当a[i]>=a[k],必有至少从j到k都有>=a[k],这才是效率高的地方*/ int main() { //freopen("in.in","r",stdin); //freopen("out.out","w",stdout); int i,j,k,m,n,k1,j1; char c; scanf("%d",&k1); while(k1--) { scanf("%d%d",&m,&n); memset(map,0,sizeof(map)); max=0; for(i=0;i<m;i++) { for(j=0;j<n;j++) { scanf("%c",&c); if(c==' '||c=='\n'||c=='\0')j--; if(c=='R'){map[i][j]=0;continue;} if(i==0&&c=='F'){map[0][j]=1;continue;} if(c=='F')map[i][j]=map[(i-1)][j]+1; } /*每行求和*/ left[0]=0; right[n-1]=n-1; for(j=1;j<n;j++) { k=j; while(k>0&&map[i][j]<=map[i][k-1]&&map[i][j])k=left[k-1]; left[j]=k; } for(j=n-2;j>=0;j--) { k=j; while(k<n-1&&map[i][j]<=map[i][k+1]&&map[i][j])k=right[k+1]; right[j]=k; } for(j=0;j<n;j++) { ae=(right[j]-left[j]+1)*map[i][j]; max=max>ae?max:ae; } } printf("%lld\n",max*3); } return 0; }
又一道类型题与hdu1505 hdu 1506 相似
只是多了一步,把字母全部尽量变成a或b或c
套用hdu1505
//hdu2870 #include<cstdio> #include<cstring> using namespace std; #define Max(a,b) (a)>(b)?(a):(b) #define N 1005 char map[N][N],m[N][N]; int left[N],right[N],num[N][N],m1,n; int solve(char test) { int i,j,k,s; memset(num,0,sizeof(num)); for(j=0;j<m1;j++) if(m[0][j]==test)num[0][j]=1; for(i=1;i<n;i++) for(j=0;j<m1;j++) { if(m[i][j]==test&&m[i-1][j]==test) num[i][j]=num[i-1][j]+1; else if(m[i][j]==test)num[i][j]=1; else num[i][j]=0; } s=0; for(i=0;i<n;i++) { left[0]=0; right[m1-1]=m1-1; for(j=1;j<m1;j++) { k=j; while(k-1>=0&&num[i][k-1]>=num[i][j])k=left[k-1]; left[j]=k; } for(j=m1-2;j>=0;j--) { k=j; while(k+1<m1&&num[i][k+1]>=num[i][j])k=right[k+1]; right[j]=k; } for(j=0;j<m1;j++) s=Max(s,(right[j]-left[j]+1)*num[i][j]); } return s; } int main() { char c; int i,j,max; while(scanf("%d%d",&n,&m1)!=EOF) { max=0; memset(map,0,sizeof(map)); memset(m,0,sizeof(m)); for(i=0;i<n;i++) for(j=0;j<m1;j++) { scanf("%c",&c); if(c=='\n'||c==' '||c=='\0')j--; else map[i][j]=m[i][j]=c; } for(i=0;i<n;i++) for(j=0;j<m1;j++) if(map[i][j]=='w'||map[i][j]=='y'||map[i][j]=='z')m[i][j]='a'; max=Max(max,solve('a')); for(i=0;i<n;i++) for(j=0;j<m1;j++) if(map[i][j]=='w'||map[i][j]=='x'||map[i][j]=='z')m[i][j]='b'; else m[i][j]=map[i][j]; max=Max(max,solve('b')); for(i=0;i<n;i++) for(j=0;j<m1;j++) if(map[i][j]=='x'||map[i][j]=='y'||map[i][j]=='z')m[i][j]='c'; else m[i][j]=map[i][j]; max=Max(max,solve('c')); printf("%d\n",max); } return 0; }