hdu 1505 1506 2870 dp小礼包

1505


思路:

读入的时候先处理一下,使得 map[i][j] 记录的是 第 i 行中 连续到第 j 列有多少个 F.

就样例而言

R F F F F F

F F F F F F

R R R F F F

F F F F F F

F F F F F F

可以被处理为

0 1 2 3 4 5

1 2 3 4 5 6

0 0 0 1 2 3

1 2 3 4 5 6

1 2 3 4 5 6

对于任意一个 map[i][j],我们如果要找到包含该点在内的最大的面积的话,只要关注这一列的状况,因为 map[i][j] 本身就记录了该行的状况。

从 第i行 开始向上找,map[i-k][j] 的最小值就代表了从 第j列开始可以向左拓展的最大宽度(类似木桶原理(?),再乘上向上找的行数,就是一块矩形的面积了,然后所有这些面积里面取最大值,就是答案。

另外考虑到可能有很多0,那么我们向上一旦找到一个0,就可以停了,显然以后的最小值都会是0,乘出来也都会是0。从图形上理解,这代表着从 map[i-k][j] 那点开始是不能够连续到该点的,更不用说向上了。

以样例的最后一行(i=6)为例

j=1时,1*1,1*2 最大值为2

j=2时,2*1,2*2 最大值为4

j=3时,3*1,3*2 最大值为6

j=4时,4*1,4*2,1*3,1*4,1*5 最大值为8

j=5时,5*1,5*2,2*3,2*4,2*5 最大值为10

j=6时,6*1,6*2,3*3,3*4,3*5 最大值为15

(上面的式子都是宽度乘高度)


后来看discuss的时候看到一种很棒的做法,后面再讲。

(其实这段代码我写的一点也不像dp)


AC代码如下:

//1505.cpp

#include <iostream>
#include <string>
#define maxn 1010
int map[maxn][maxn],minim[maxn][maxn];
using namespace std;
int main()
{
	int T,m,n,i,j,ans,k,x,anss;
	string s;
	char ch;
	cin >> T;
	while (T--)
	{
		cin >> m >> n;
		for (i=1;i<=m;++i)
			for (j=1;j<=n;++j)
			{ 
				cin >> ch;
				if (ch=='F') 
					map[i][j] = map[i][j-1]+1;
				else
					map[i][j] = 0;
			}
		anss = 0;
		for (i=1;i<=m;++i)
			for (j=1;j<=n;++j)
			{
				x = ans = map[i][j];
				for (k=1;k<=i-1;++k)
				{
					if (map[i-k][j]==0)
						break;
					x = min(x,map[i-k][j]);
					ans = max(ans,x*(k+1));
				}
				anss = max(anss,ans);
			}
		cout << anss*3 << endl;
		getline(cin,s);
	}
	return 0;
}

discuss里面有一种做法,点击打开链接,是先预处理好l,r,h数组。

其中一个很棒的想法是,对于l数组,每次和左边比较的时候,不需要一个一个比过去,因为如果 h[i-1]>=h[i] 就这样去判断 l[i-1] 所指的位置的前一个位置是不是满足这个条件然后一直往前找,这样大大减少了循环次数。





1506



其实和1505一样的道理,只是换成了一维的
但是要注意 long long

看discuss里面学到了很棒的几个做法

一个是分治,用了栈,点击打开链接

另一个是单调栈做法,感觉学习到了很多,单调栈相关


分治AC代码如下:

//1506.cpp

#include <iostream>
#include <stack>
#define maxn 100010
long long a[maxn];
using namespace std;
long long maxi(long long l,long long r);
int main()
{
//	freopen("1506.in","r",stdin);
//	freopen("1506.out","w",stdout);
	
	long long n,i;
	while (cin >> n && n)
	{
		for (i=0;i<n;++i)
			cin >> a[i];
		cout << maxi(0,n-1) << endl;
	}
	
//	fclose(stdin);
//	fclose(stdout);
	return 0;
}
long long maxi(long long l,long long r)
{
	if (r-l==1)
		return max(max(a[r],a[l]),min(a[r],a[l])*2);
	if (r==l)
		return a[l];
//	cout << l << " " << r << endl;
	stack<long long> left,right;
	long long i,j,low,len,ans;
	long long mid = (l+r) >> 1;
	long long maxl = maxi(l,mid);
//	cout << l << " " << r << " " << maxl << endl;
	long long maxr = maxi(mid+1,r);
//	cout << l << " " << r << " " << maxr << endl;
	for (i=l;i<=mid;++i)
		left.push(a[i]);
	for (i=r;i>mid;--i)
		right.push(a[i]);
	low = INT_MAX;
	len = ans = 0;
	while (!left.empty() || !right.empty())
	{
		if (!left.empty() && left.top()>=low)
		{
			++ len;
			ans = max(ans,low*len);
			left.pop();
		}
		else if (!right.empty() && right.top()>=low)
		{
			++ len;
			ans = max(ans,low*len);
			right.pop();
		}
		else if (!left.empty() && !right.empty())
		{
			if (left.top() <= right.top())
			{
				++ len;
				low = right.top();
				ans = max(ans,low*len);
				right.pop();
			}
			else
			{
				++ len;
				low = left.top();
				ans = max(ans,low*len);
				left.pop();
			}
		}
		else if (!left.empty())
		{
			++ len;
			low = min(low,left.top());
			ans = max(ans,len*low);
			left.pop();
		}
		else if (!right.empty())
		{
			++ len;
			low = min(low,right.top());
			ans = max(ans,len*low);
			right.pop();
		}
	}
//	cout << l << " " << r << " " << max(max(maxl,maxr),ans) << endl;
	return max(max(maxl,maxr),ans);
}


单调栈AC代码如下:

//1506.cpp

#include <iostream>
#include <cstdio>
#include <stack>
using namespace std;
stack<long long> l,r;
#define maxn 100010
long long le[maxn],ri[maxn],a[maxn];
int main()
{
//	freopen("1506.in","r",stdin);
//	freopen("15062.out","w",stdout);
	long long n,i,ans,x;
	while (cin >> n && n)
	{
		while (!l.empty())
			l.pop();
		while (!r.empty())
			r.pop();
		for (i=0;i<n;++i)
			cin >> a[i];
		l.push(0);
		le[0] = 0;
		r.push(n-1);
		ri[n-1] = n-1;
		for (i=1;i<n;++i)
		{
			if (a[l.top()] >= a[i])
			{
				while (!l.empty() && a[l.top()] >= a[i])
				{
					x = l.top();
					l.pop();
				}
				le[i] = le[x];
			}
			else
				le[i] = i;
			l.push(i);
		}
//		for (i=0;i<n;++i)
//			cout << le[i] << " ";
//		cout << endl;
		for (i=n-2;i>=0;--i)
		{
			if (a[r.top()] >= a[i])	
			{
				while (!r.empty() && a[r.top()] >= a[i])
				{
					x = r.top();
					r.pop();
				}
				ri[i] = ri[x];
			}
			else
				ri[i] = i;
			r.push(i);
		}
//		for (i=0;i<n;++i)
//			cout << ri[i] << " ";
		ans = 0;
		for (i=0;i<n;++i)
			ans = max(ans,(ri[i]-le[i]+1)*a[i]);
		cout << ans << endl;
	}
//	fclose(stdin);
//	fclose(stdout);
	return 0;
}



2870

其实就是做了三遍1505,分别对 a,b,c 的状态进行记录


AC代码如下:

//2870.cpp

#include <iostream>
using namespace std;
#define maxn 1010
#include <cstring>
struct tri
{
	short a,b,c;
};
tri h[maxn][maxn],l[maxn][maxn],r[maxn][maxn];
char c[maxn][maxn];
int main()
{
//	freopen("2870.in","r",stdin);
//	freopen("2870.out","w",stdout);
	int m,n,i,j,k,ans;
	while (cin >> m >> n)
	{
	memset(h,0,sizeof(h));
	for (i=1;i<=m;++i)
		for (j=1;j<=n;++j)
		{
			cin >> c[i][j];
			if (c[i][j] == 'a' || c[i][j] == 'w' || c[i][j] == 'y' || c[i][j] == 'z')
				h[i][j].a = h[i-1][j].a + 1;
			if (c[i][j] == 'b' || c[i][j] == 'w' || c[i][j] == 'x' || c[i][j] == 'z')
				h[i][j].b = h[i-1][j].b + 1;
			if (c[i][j] == 'c' || c[i][j] == 'x' || c[i][j] == 'y' || c[i][j] == 'z')
				h[i][j].c = h[i-1][j].c + 1;
		}
	for (i=1;i<=m;++i)
		for (j=1;j<=n;++j)
		{
			if (h[i][j].a)
			{
				k = j;
				while (h[i][k-1].a >= h[i][j].a && (c[i][k-1] == 'a' || c[i][k-1] == 'w' || c[i][k-1] == 'y' || c[i][k-1] == 'z'))
					-- k;
				l[i][j].a = k;
			}
			if (h[i][j].b)
			{
				k = j;
				while (h[i][k-1].b >= h[i][j].b && (c[i][k-1] == 'b' || c[i][k-1] == 'w' || c[i][k-1] == 'x' || c[i][k-1] == 'z'))
					-- k;
				l[i][j].b = k;
			}
			if (h[i][j].c)
			{
				k = j;
				while (h[i][k-1].c >= h[i][j].c && (c[i][k-1] == 'c' || c[i][k-1] == 'x' || c[i][k-1] == 'y' || c[i][k-1] == 'z'))
					-- k;
				l[i][j].c = k;
			}
		}
	for (i=1;i<=m;++i)
		for (j=1;j<=n;++j)
		{
			if (h[i][j].a)
			{
				k = j;
				while (h[i][k+1].a >= h[i][j].a && (c[i][k+1] == 'a' || c[i][k+1] == 'w' || c[i][k+1] == 'y' || c[i][k+1] == 'z'))
					++ k;
				r[i][j].a = k;
			}
			if (h[i][j].b)
			{
				k = j;
				while (h[i][k+1].b >= h[i][j].b && (c[i][k+1] == 'b' || c[i][k+1] == 'w' || c[i][k+1] == 'x' || c[i][k+1] == 'z'))
					++ k;
				r[i][j].b = k;
			}
			if (h[i][j].c)
			{
				k = j;
				while (h[i][k+1].c >= h[i][j].c && (c[i][k+1] == 'c' || c[i][k+1] == 'x' || c[i][k+1] == 'y' || c[i][k+1] == 'z'))
					++ k;
				r[i][j].c = k;
			}
		}
	ans = 0;

	for (i=1;i<=m;++i)
		for (j=1;j<=n;++j)
		{
			if (l[i][j].a)
				ans = max(ans,(r[i][j].a-l[i][j].a+1) * h[i][j].a);
			if (l[i][j].b)
				ans = max(ans,(r[i][j].b-l[i][j].b+1) * h[i][j].b);
			if (l[i][j].c)
				ans = max(ans,(r[i][j].c-l[i][j].c+1) * h[i][j].c);
		}
	cout << ans << endl;
}
//	fclose(stdin);
//	fclose(stdout);
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值