hdu2870(dp+单调栈优化)

11 篇文章 0 订阅
1 篇文章 0 订阅

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2870

Largest Submatrix

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2835    Accepted Submission(s): 1373


Problem Description
Now here is a matrix with letter 'a','b','c','w','x','y','z' and you can change 'w' to 'a' or 'b', change 'x' to 'b' or 'c', change 'y' to 'a' or 'c', and change 'z' to 'a', 'b' or 'c'. After you changed it, what's the largest submatrix with the same letters you can make?
 

Input
The input contains multiple test cases. Each test case begins with m and n (1 ≤ m, n ≤ 1000) on line. Then come the elements of a matrix in row-major order on m lines each with n letters. The input ends once EOF is met.
 

Output
For each test case, output one line containing the number of elements of the largest submatrix of all same letters.
 

Sample Input
 
 
2 4 abcw wxyz
 

Sample Output
 
 
3
 

Source
 

Recommend
gaojie   |   We have carefully selected several similar problems for you:   2830  2577  1505  2845  1069 
 


思路:我的第一道单调栈题。之前看了白书上的例题,但不是特别理解,这次正好重新又学了一遍。

这道题和hdu1505十分相似,就是相当于统计三遍。也就是分别把矩阵中的w,x,y,z全转成a,b,c。然后算三次。为了计算方便,把字母矩阵换成01矩阵,见代码。值得注意的是,经典的单调栈中每个元素的高度h[i]是一维的,而这题是二维的,用h[i][j]记录即可,每一行都用一次单调栈即可,详见代码。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
char s[1010][1010];
int scopy[1010][1010];
int h[1010][1010];
int l[1010];
int r[1010];
int st[1010];
int n,m;
ll ans1;
ll ans2;
ll ans3;
ll solve1()
{
	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<m;j++)
		{
			if(s[i][j]=='a'||s[i][j]=='w'||s[i][j]=='y'||s[i][j]=='z')
			{
				scopy[i][j]=1;
			}
			else
			{
				scopy[i][j]=0;
			}
			if(scopy[i][j]==1)
			{
				h[i][j]=h[i-1][j]+1;
			}
			else
			h[i][j]=0;
		}
	}
	ans1=0;
	int t;
	for(int i=1;i<=n;i++)
	{
		t=0;
		for(int j=0;j<m;j++)
		{
			while(t>0&&h[i][st[t-1]]>=h[i][j])
			t--;
			l[j]= t==0 ? 0 : (st[t-1]+1);
			st[t++]=j;
		}
		t=0;
		for(int j=m-1;j>=0;j--)
		{
			while(t>0&&h[i][st[t-1]]>=h[i][j])
			t--;
			r[j]= t==0 ? m : st[t-1];
			st[t++]=j;
		}
		for(int j=0;j<m;j++)
		ans1=max(ans1,(ll)(h[i][j]*(r[j]-l[j])));
	}
	return ans1;
}
ll solve2()
{
	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<m;j++)
		{
			if(s[i][j]=='b'||s[i][j]=='w'||s[i][j]=='x'||s[i][j]=='z')
			{
				scopy[i][j]=1;
			}
			else
			{
				scopy[i][j]=0;
			}
			if(scopy[i][j]==1)
			{
				h[i][j]=h[i-1][j]+1;
			}
			else
			h[i][j]=0;
		}
	}
	ans2=0;
	int t;
	for(int i=1;i<=n;i++)
	{
		t=0;
		for(int j=0;j<m;j++)
		{
			while(t>0&&h[i][st[t-1]]>=h[i][j])
			t--;
			l[j]= t==0 ? 0 : (st[t-1]+1);
			st[t++]=j;
		}
		t=0;
		for(int j=m-1;j>=0;j--)
		{
			while(t>0&&h[i][st[t-1]]>=h[i][j])
			t--;
			r[j]= t==0 ? m : st[t-1];
			st[t++]=j;
		}
		for(int j=0;j<m;j++)
		ans2=max(ans2,(ll)(h[i][j]*(r[j]-l[j])));
	}
	return ans2;
}
ll solve3()
{
	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<m;j++)
		{
			if(s[i][j]=='c'||s[i][j]=='x'||s[i][j]=='y'||s[i][j]=='z')
			{
				scopy[i][j]=1;
			}
			else
			{
				scopy[i][j]=0;
			}
			if(scopy[i][j]==1)
			{
				h[i][j]=h[i-1][j]+1;
			}
			else
			h[i][j]=0;
		}
	}
	ans3=0;
	int t;
	for(int i=1;i<=n;i++)
	{
		t=0;
		for(int j=0;j<m;j++)
		{
			while(t>0&&h[i][st[t-1]]>=h[i][j])
			t--;
			l[j]= t==0 ? 0 : (st[t-1]+1);
			st[t++]=j;
		}
		t=0;
		for(int j=m-1;j>=0;j--)
		{
			while(t>0&&h[i][st[t-1]]>=h[i][j])
			t--;
			r[j]= t==0 ? m : st[t-1];
			st[t++]=j;
		}
		for(int j=0;j<m;j++)
		ans3=max(ans3,(ll)(h[i][j]*(r[j]-l[j])));
	}
	return ans3;
}
int main()
{
	  while(scanf("%d%d",&n,&m)!=EOF)
   {
	   for(int i=1;i<=n;i++)
	   {
	      getchar();
		  scanf("%s",s[i]);
	   }
	   ll res=0;
	   ll t1=solve1();
	   ll t2=solve2();
	   ll t3=solve3();
	   res=max(t1,max(t2,t3));
	   printf("%lld\n",res);
   }
	return 0;
} 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值