突然在做这个题目的时候,想到高中数学老师,那句经典的口头禅
"两个数的我不做,我只会做一个数"^_^!
分治的思想:
首先题目要求的是“区间的价值”为一段区间的最大值*最小值,对于长度为1∼n的区间,最大价值的区间价值分别是多少。
想法如下:
如果在这个区间里我先固定了最小值,也就是先去确定最小值是多少,然后我去计算以最小值为中心,左右两边的区间价值,然后我就可以更新整个区间的最大价值,然后二分调用solve(l,p-1)和solve(p+1,r)这两个区间里最小值然后确定每一个区间段的最大值,再去更新整个区间的最大价值!
solve(l,r)来求出区间[l,r]中各种区间长度的最大价值。
"两个数的我不做,我只会做一个数"^_^!
分治的思想:
首先题目要求的是“区间的价值”为一段区间的最大值*最小值,对于长度为1∼n的区间,最大价值的区间价值分别是多少。
想法如下:
如果在这个区间里我先固定了最小值,也就是先去确定最小值是多少,然后我去计算以最小值为中心,左右两边的区间价值,然后我就可以更新整个区间的最大价值,然后二分调用solve(l,p-1)和solve(p+1,r)这两个区间里最小值然后确定每一个区间段的最大值,再去更新整个区间的最大价值!
solve(l,r)来求出区间[l,r]中各种区间长度的最大价值。
随着区间变长,如果最小值是固定的,那么最大值只有可能越来越大,价值才会越来越大!
题解报告给出了单调栈的一种解决办法,待我做完之后再更新!
代码:
/*
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#define LL long long
using namespace std;
const int MAXN = 1e5+5;
LL a[MAXN],temp[MAXN],ans[MAXN];
void solve(int l,int r)
{
if(l>r)
return ;
int p=0;
for(int i = l;i<=r;i++)
{
if(!p||a[i]<a[p])
p = i;
}
int w = r-l+1;
for(int i = 1;i<=w;i++)
temp[i] = 0;
LL pre = 0;
//遍历一遍区间获得他们的最大区间值
for(int i = p-1;i>=l;i--)
{
if(temp[p-i+1]<max(pre,(LL)a[p]*a[i]))
{
temp[p-i+1] = max(pre,(LL)a[p]*a[i]);
//因为最小值固定下来了,也就是看最大值哪个大
//短区间的值可以给长区间做更新(也就是短区间的最大值更大)
pre=temp[p-i+1];
}
}
pre = 0;
for(int i = p+1;i<=r;i++)
{
if(temp[i-p+1]<max(pre,(LL)a[p]*a[i]))
{
temp[i-p+1] = max(pre,(LL)a[p]*a[i]);
pre = temp[i-p+1];
}
}
ans[1] = max(ans[1],a[p]*a[p]);
pre = 0;
//整体的区间长度的最大价值更新操作
for(int i = 2;i<=w;i++)
{
if(ans[i]<max(pre,temp[i]))
{
ans[i]=max(pre,temp[i]);
}
pre = max(pre,temp[i]);
}
solve(l,p-1);
solve(p+1,r);
}
int main()
{
freopen("in2.txt","r",stdin);
//freopen("out1.txt","w",stdout);
int n;
while(~scanf("%d",&n))
{
memset(ans,0,sizeof(ans));
for(int i = 0;i<MAXN;i++)
temp[i] = 0;
for(int i =1;i<=n;i++)
scanf("%I64d",&a[i]);
solve(1,n);
for(int i = 1;i<=n;i++)
{
printf("%I64d\n",ans[i]);
}
}
return 0;
}