您的位置:首页 > 其它

hdu 区间的价值(RMQ+扫描)

2016-05-22 21:58 447 查看


区间的价值

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

Input

多组测试数据

第一行一个数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


思路:用rmq求出所有区间的最大值,然后l[i]表示i左边有几个不小于i的数,r[i]同理。

那么我们可以求出长度为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;
long long dp
[20];
int l
,r
;
long long ans
,b
;
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: