区间的价值
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 127 Accepted Submission(s): 58
Problem Description
我们定义“区间的价值”为一段区间的最大值*最小值。
一个区间左端点在 L ,右端点在 R ,那么该区间的长度为 (R−L+1) 。
现在聪明的杰西想要知道,对于长度为 k 的区间,最大价值的区间价值是多少。
当然,由于这个问题过于简单。
我们肯定得加强一下。
我们想要知道的是,对于长度为 1∼n 的区间,最大价值的区间价值分别是多少。
样例解释:
长度为 1 的最优区间为 2−2 答案为 6∗6
长度为 2 的最优区间为 4−5 答案为 4∗4
长度为 3 的最优区间为 2−4 答案为 2∗6
长度为 4 的最优区间为 2−5 答案为 2∗6
长度为5的最优区间为 1−5 答案为 1∗6
一个区间左端点在 L ,右端点在 R ,那么该区间的长度为 (R−L+1) 。
现在聪明的杰西想要知道,对于长度为 k 的区间,最大价值的区间价值是多少。
当然,由于这个问题过于简单。
我们肯定得加强一下。
我们想要知道的是,对于长度为 1∼n 的区间,最大价值的区间价值分别是多少。
样例解释:
长度为 1 的最优区间为 2−2 答案为 6∗6
长度为 2 的最优区间为 4−5 答案为 4∗4
长度为 3 的最优区间为 2−4 答案为 2∗6
长度为 4 的最优区间为 2−5 答案为 2∗6
长度为5的最优区间为 1−5 答案为 1∗6
Input
多组测试数据
第一行一个数 n(1≤n≤100000) 。
第二行 n 个正整数 (1≤ai≤109) ,下标从 1 开始。
由于某种不可抗力, ai 的值将会是 1∼109 内<b style="color:red;">随机产生</b>的一个数。(除了样例)
第一行一个数 n(1≤n≤100000) 。
第二行 n 个正整数 (1≤ai≤109) ,下标从 1 开始。
由于某种不可抗力, ai 的值将会是 1∼109 内<b style="color:red;">随机产生</b>的一个数。(除了样例)
Output
输出共
n
行,第
i
行表示区间长度为
i
的区间中最大的区间价值。
Sample Input
5 1 6 2 4 4
Sample Output
36 16 12 12 6
那么我们可以求出长度为r[i]+l[i]-1的一个区间最小值是i,最大值可以用rmq求出,两者相乘即可得到长度为r[i]+l[i]-1的一个解(此解不一定最优)
我们此时知道长度为n的区间解肯定是最优的(只有一种情况),那么可以用动态规划的思想。
b[i]=max(b[i+1],ans[i]);
ans[i]是已知的长度为i的一个解,那么此时我们还需要求出大于i的所有区间里长度为i的子区间的最大值
b[i+1]则是已知的长度为i+1时的最优解,既然i+1此时已经达到了最优,我们从中取i个数,也一定能取到b[i+1],也就是说,长度为i的区间的值起码会是长度为i+1的区间的值
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define N 100080
int a[N],n;
long long dp[N][20];
int l[N],r[N];
long long ans[N],b[N];
void make_rmq()///建立dp数组,l[i]保存i点左边有几个不小于a[i]的数,r[i]同理
{
for(int i=0;i<n;i++)
dp[i][0]=a[i];
for(int j=1;(1<<j)<=n;j++)
{
for(int i=0;i+(1<<j)-1<n;i++)
{
dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
}
for(int i=0;i<n;i++)
l[i]=r[i]=1;
for(int i=1;i<n;i++)
{
for(int j=i-1;j>=0;)
{
if(a[j]>=a[i])
{
l[i]+=l[j];
j=j-l[j];
}
else break;
}
}
for(int i=n-1;i>=0;i--)
{
for(int j=i+1;j<n;)
{
if(a[j]>=a[i])
{
r[i]+=r[j];
j+=r[j];
}
else break;
}
}
}
long long get_rmq(int s,int t)///获得s-t间最大值
{
if(s==t) return a[s];
int k=(int)(log(t-s+1.0)/log(2.0));
return max(dp[s][k],dp[t-(1<<k)+1][k]);
}
void solve()
{
memset(ans,0,sizeof(ans));
for(int i=0;i<n;i++)///ans[i]表示长度为i时候的最大值(不一定是最后的解)
{
int ll=l[i],rr=r[i];
ans[rr+ll-1]=max(ans[rr+ll-1],a[i]*get_rmq(i-ll+1,i+rr-1));
}
b[n+1]=-1;
for(int i=n;i>=1;i--)///比较ans[i]和i+1的最优解,得出最大的
b[i]=max(b[i+1],ans[i]);
for(int i=1;i<=n;i++)
printf("%lld\n",b[i]);
}
int main()
{
while(~scanf("%d",&n))
{
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
make_rmq();
solve();
}
return 0;
}