2016百度之星 hdu 5696 RMQ+单调栈



链接:戳这里


区间的价值
Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

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


思路:

先用单调栈处理出以当前ai为最小值能扩充到的最大的左右区间

然后算出每个ai所在的区间长度的值,已知了当前的最小ai和以ai为最小值的区间[l,r]

直接用RMQ求出[l,r]的区间最大值,则dp[r-l+1]=max(dp[r-l+1],ai*RMQ(l,r))

然后在对于没算出的长度,继承一下上面的就可以了  这里需要满足dp[len-1]>=dp[len]


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<iomanip>
#include<cmath>
#define mst(ss,b) memset((ss),(b),sizeof(ss))
#define maxn 0x3f3f3f3f
#define MAX 1000100
///#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
typedef unsigned long long ull;
#define INF (1ll<<60)-1
using namespace std;
int n;
int a[200100];
struct node{
    int pos,v;
    node(int pos=0,int v=0):pos(pos),v(v){}
};
stack <node> qu;
int L[200100],R[200100];
int f[200100][20];
int query(int l,int r){
    int m=log(r-l+1)/log(2);
    return max(f[l][m],f[r-(1<<m)+1][m]);
}
ll dp[200100];
int main(){
    while(scanf("%d",&n)!=EOF){
        mst(L,0);
        mst(R,0);
        mst(f,0);
        mst(dp,0);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        while(!qu.empty()) qu.pop();
        qu.push(node(0,0));
        for(int i=1;i<=n;i++){
            while(!qu.empty()){
                node now=qu.top();
                if(a[i]<now.v){
                    R[now.pos]=i-1;
                    qu.pop();
                } else {
                    qu.push(node(i,a[i]));
                    break;
                }
            }
        }
        while(!qu.empty()) {
            node now=qu.top();
            qu.pop();
            R[now.pos]=n;
        }
        qu.push(node(0,0));
        for(int i=n;i>=1;i--){
            while(!qu.empty()){
                node now=qu.top();
                if(a[i]<now.v){
                    L[now.pos]=i+1;
                    qu.pop();
                } else {
                    qu.push(node(i,a[i]));
                    break;
                }
            }
        }
        while(!qu.empty()){
            node now=qu.top();
            qu.pop();
            L[now.pos]=1;
        }
        /*for(int i=1;i<=n;i++) cout<<L[i]<<" ";
        cout<<endl;
        for(int i=1;i<=n;i++) cout<<R[i]<<" ";
        cout<<endl;*/
        for(int i=1;i<=n;i++) f[i][0]=a[i];
        int m=log(n)/log(2);
        for(int i=1;i<=m;i++){
            for(int j=n;j>=1;j--){
                f[j][i]=f[j][i-1];
                if(j+(1<<(i-1))<=n)
                    f[j][i]=max(f[j][i],f[j+(1<<(i-1))][i-1]);
            }
        }
        for(int i=1;i<=n;i++){
            int len=R[i]-L[i]+1;
            dp[len]=max(dp[len],(ll)query(L[i],R[i])*a[i]);
        }
        ll mx=0;
        for(int i=n;i>=1;i--){
            mx=max(dp[i+1],mx);
            dp[i]=max(dp[i],mx);
        }
        for(int i=1;i<=n;i++) cout<<dp[i]<<endl;
    }
    return 0;
}



评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值