1001 区间的价值:

   RMQ+扫描法

  我们预处理RMQ求任意区间的最大值

  预处理出以a[i]为最小值 能向左延伸 向右延伸的 L[i], R[i]

  那么对于 一个答案 (L[i], R[i]) *rmq(L[i],R[i]) 为此长度的答案,我们可以发现他是可以更新到小于其长度的所有长度答案的,更新就好

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include<map>
using namespace std;
const int N = 1e5+10, M = 30005, mod = 1e9 + 7, inf = 0x3f3f3f3f;
typedef long long ll;
ll a[N],dp[N][30],ans[N],las[N];
int l[N],r[N],n;
void RMQ_init() {
    memset(dp,0,sizeof(dp));
    memset(l,0,sizeof(l));
    memset(r,0,sizeof(r));
    for(int i=1;i<=n;i++) dp[i][0] = a[i];
    for(int j=1;(1<<j)<=n;j++) {
        for(int i=1;i + (1<<j) - 1 <= n; i++) {
            if(dp[i][j-1] > dp[i+(1<<(j-1))][j-1])
                dp[i][j] =  dp[i][j-1];
            else {
                 dp[i][j] =  dp[i+(1<<(j-1))][j-1];
            }
        }
    }
     l[1] = 1;a[0] = -1000;a[n+1] = -10000;
    for(int i=2;i<=n;i++) {
        int tmp = i-1;
        while(a[i]<=a[tmp]) tmp = l[tmp]-1;
        l[i] = tmp+1;
    }
    r[n] = n;
    for(int i=n-1;i>=1;i--) {
         int tmp = i+1;
        while(a[i]<=a[tmp]) tmp = r[tmp] + 1;
        r[i] = tmp - 1;
    }
}
ll rmq(int l,int r) {
    if(l==r) return a[l];
    int k = (int) (log((double) r-l+1) / log(2.0));
    return max(dp[l][k], dp[r - (1<<k) + 1][k]);
}
int main() {
    while(scanf("%d",&n)!=EOF) {
        for(int i=1;i<=n;i++) scanf("%I64d",&a[i]);
        RMQ_init();
        for(int i=1;i<=n;i++) ans[i] = -1;
        for(int i=1;i<=n;i++) {
            ll mm = rmq(l[i],r[i]);
            ans[r[i]-l[i]+1] = max(mm*a[i],ans[r[i]-l[i]+1]);
        }
        las[n+1] = -1;
        for(int i=n;i>=1;i--) {
            las[i] = max(ans[i],las[i+1]);
        }
        for(int i=1;i<=n;i++) printf("%I64d\n",las[i]);
    }
    return 0;
}
View Code

相关文章: