之所以把这两题放一块呢。。。是因为1505 是1506的深化!
1506是求最大矩形覆盖(说到这里,我觉得好多覆盖问题都是用dp解决的啊,有树上的最少覆盖条件:
昨天做的那个 POJ 1463 && HDU 1054 Strategic Game (树形DP);有线性问题的覆盖,比如这两题)
hdu 1506 和那个POJ 2796 Feel Good应该就是一样的。代码略改就可以提交了。
都是向左右找比当前位置大的数,记录能延伸到的最远距离,只是这题矩形的宽度是1,比那题还要简单。
要注意的是开始写的向两边找没有用到dp中递推的思想,而是每次都找一遍tle了。。
下面看一下tle的代码:需要优化的地方在里面有标注
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
__int64 a[100010];
int le[100010],ri[100010];
__int64 dp[100010];
int main()
{
int n,tmp;
__int64 ans;
while(scanf("%d",&n)&&n)
{
memset(dp,0,sizeof(dp));
memset(le,0,sizeof(le));
memset(ri,0,sizeof(ri));
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++) //可以用递推优化。
{
tmp=i;
while( tmp>=1 &&a[tmp]>=a[i])
tmp--;
le[i]=tmp+1;
}
for(int i=1;i<=n;i++)
{
tmp=i;
while(tmp<=n && a[tmp]>=a[i])
tmp++;
ri[i]=tmp-1;
}
//for(int i=1;i<=n;i++)
// printf("%d %d %d %d\n",i,a[i],le[i],ri[i]);
ans=-1;
for(int i=1;i<=n;i++)
{
dp[i]=a[i]*(ri[i]-le[i]+1);
if(dp[i]>ans)
ans=dp[i];
}
printf("%I64d\n",ans);
}
return 0;
}
//HDU 1506
//tle
然后就是利用了找最优子结构的思想,把左右的最大延伸范围记录下来
只需要和相邻的比较就可以了。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<cmath>
#include<cstdlib>
#include<cctype>
#include<stack>
#include<vector>
#include<queue>
using namespace std;
__int64 a[100010];
int l[100010],r[100010];
__int64 ans,tmp;
int main()
{
int n,minn,le,ri;
while(scanf("%d",&n)&&n)
{
for(int i=1;i<=n;i++)
{
scanf("%I64d",&a[i]);
l[i]=r[i]=i;
}
for(int i=2;i<=n;i++)
{
while(l[i]>1 && a[l[i]-1]>=a[i]) //要注意的地方。
l[i]=l[l[i]-1];
}
for(int i=n-1;i>=0;i--)
{
while(r[i]<n && a[r[i]+1]>=a[i])
r[i]=r[r[i]+1];
}
ans=-1;
for(int i=1;i<=n;i++)
{
tmp=a[i]*(r[i]-l[i]+1);
if(tmp>ans)
{
ans=tmp;
}
}
printf("%I64d\n",ans);
}
return 0;
}
hdu 1505 可以转化为 在一个01 矩阵里面找一个最大的全 0 矩阵 , 先求出每个 0 能够向上找到的 0 的个数 。
然后像1506那样逐行进行类似的运算求最大值。
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int a[1005][1005];
int le[1005],ri[1005];
int main()
{
int T,tmp,ans,m,n;
char str[10];
scanf("%d",&T);
while(T--)
{
memset(a,0,sizeof(a));
scanf("%d%d",&m,&n);
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
scanf("%s",str);
if(str[0]=='F')
a[i][j]=a[i-1][j]+1;
else a[i][j]=0;
}
}
/*for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
printf("%d ",a[i][j]);
printf("\n");
}*/
ans=-1;
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++) //每次都要重新把le[j]和ri[j]
le[j]=ri[j]=j; //初始化为本身
for(int j=2;j<=n;j++)
{
if(le[j]>1 && a[i][le[j]-1]>=a[i][j])
le[j]=le[le[j]-1];
}
for(int j=n-1;j>=1;j--)
{
if(ri[j]<n && a[i][ri[j]+1]>=a[i][j])
ri[j]=ri[ri[j]+1];
}
for(int j=1;j<=n;j++)
{
tmp=a[i][j]*(ri[j]-le[j]+1);
if(tmp>ans)
ans=tmp;
}
}
printf("%d\n",ans*3);
}
return 0;
}