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; }