Codeforces Round #622 (Div. 2)—C—Skyscrapers (easy||hard version)

题目链接:C—Skyscrapers

C1的话可以直接暴力做O(N^2),C2的话数据范围太大,,思路一样,但是复杂度要优化;

C1 - Skyscrapers (easy version)

满足题目中要求的序列一定是一个单峰序列(包括单调),只有单峰序列才满足不存在两边大中间小的情况;所以每个点都可以构成单峰序列,只不过构成的序列值总和不一样而已,暴力枚举n个点,然后取构成单峰序列总和最大的那个点即可;数据范围1≤n≤1000,所以O(N^2)复杂度能过;

#include 
using namespace std;
typedef long long ll;
ll a[100005];
int main()
{
	int n;
	cin >>n;
	for(int i=1;i<=n;i++) cin >>a[i];
	ll maxx=-0x3f3f3f3f,res,ans=-1;
	for(int i=1;i<=n;i++)
	{
		ll sum=a[i],res=a[i];
		for(int j=i-1;j>=1;j--)
		{
			if(a[j]<res)
			{
				sum+=a[j];
				res=a[j];
			}
			else sum+=res;
		}
		res=a[i];
		for(int j=i+1;j<=n;j++)
		{
			if(a[j]<res)
			{
				sum+=a[j];
				res=a[j];
			}
			else sum+=res;
		}
		if(sum>maxx)
		{
			ans=i;
			maxx=sum;
		}
	}
	res=a[ans];
	for(int i=ans-1;i>=0;i--)
	{
		if(a[i]<res) res=a[i];
		else a[i]=res;
	}
	res=a[ans];
	for(int i=ans+1;i<=n;i++)
	{
		if(a[i]<res) res=a[i];
		else a[i]=res;
	}
	for(int i=1;i<=n;i++) cout <<a[i]<<" ";
}

.
.

C2 - Skyscrapers (hard version)

Codeforces Round #622 (Div. 2)—C—Skyscrapers (easy||hard version)_第1张图片
数据加强之后如果还是两层循环暴力会超时,这个时候,思路还是一样的,但是不是枚举每个点了,而是用单调栈维护;
考虑第i个当最高点的时候,左边的最大总和,而这个是可以递推的,因为当mi>=mi-1的时候第i个可以直接取mi加上去,而当mi 中间求和的时候可以用单调栈维护下标,然后记录比当前数小的最近的数的下标是多少;然后再求和;(代码压缩的比较厉害,都放在两个循环里了,实际上求和过程拆开写会比较清楚一点)
(一个单调栈维护,花了我一天的时间,果然,知道单调栈是啥,还是不会用啊)

#include 
using namespace std;
typedef long long ll;
const int N=500005;
ll a[N],l[N],r[N],res,cnt;
ll L[N],R[N];
int main()
{
	int n;
	cin >>n;
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	stack<int> x,y;
	for(int i=1;i<=n;i++)
	{
		res=a[i];
		while(!x.empty()&&a[x.top()]>res) x.pop();
		if(x.empty()) l[i]=0;
		else l[i]=x.top();
		L[i]=L[l[i]]+(i-l[i])*a[i];
		x.push(i);
	}
	ll maxx=-0x3f3f3f3f,j;
	for(int i=n;i>=1;i--)
	{
		res=a[i];
		while(!y.empty()&&a[y.top()]>res) y.pop();
		if(y.empty()) r[i]=n+1;
		else r[i]=y.top();
		R[i]=R[r[i]]+(r[i]-i)*a[i];
		y.push(i);
		if(L[i]+R[i]-a[i]>maxx) maxx=L[i]+R[i]-a[i],j=i;
	}
	res=a[j];
	for(int i=j-1;i>=1;i--)
	{
		if(a[i]>res) a[i]=res;
		else res=a[i];
	}
	res=a[j];
	for(int i=j+1;i<=n;i++)
	{
		if(a[i]>res) a[i]=res;
		else res=a[i];
	}
	for(int i=1;i<=n;i++) printf("%d ",a[i]);
}

你可能感兴趣的:(思维)