区间的价值
从1到n分别假设每个数字为区间中的最小值。当假设a[i]为区间最小值时,区间最大值可能在左侧也可能在右侧,两种情况下处理的方式类似,这里只描述一下在左边时的情形。首先从a[i-1]开始向左边找到一个当a[i]为区间最小值时可以作为区间最大值的a[j],则应满足的条件为a[j]>a[i]且当j<k<i时,a[j]>=a[k]>=a[i]。然后从a[j-1]继续向左找到最小的下标l使得当l<=k<j时,a[j]>=a[k]>=a[i]。从a[i+1]向右找到最大的下标r使得当i<k<=r时,a[j]>=a[k]>=a[i]。区间左端点在[l,j],右端点在[i,r]的区间最大值和最小值均分别为a[j]和a[i],其长度最短为i-j+1,最长为r-l+1,以a[i]*a[j]的值更新相应的ans。重复此过程,直到找不到满足条件的j。
#include <stdio.h> #include <string.h> long long a[100005], ans[100005]; int main() { int n, l, r, j; long long max; while (scanf("%d", &n) != EOF) { for (int i = 1; i <= n; i++) { scanf("%lld", &a[i]); } memset(ans, 0, sizeof(ans)); for (int i = 1; i <= n; i++) { j = r = i; max = a[i]; while (j >= 1) { if (a[j] < max) { break; } l = j; while (r + 1 <= n && a[i] <= a[r + 1] && a[r + 1] <= a[j]) { r++; } while (l - 1 >= 1 && a[i] <= a[l - 1] && a[l - 1] <= a[j]) { l--; } long long tmp = a[i] * a[j]; for (int k = (i - j + 1); k <= (r - l + 1); k++) { if (tmp > ans[k]) { ans[k] = tmp; } } max = a[j]; j = l - 1; } j = l = i; max = a[i]; while (j <= n) { if (a[j] < max) { break; } r = j; while (l - 1 >= 1 && a[i] <= a[l - 1] && a[l - 1] <= a[j]) { l--; } while (r + 1 <= n && a[i] <= a[r + 1] && a[r + 1] <= a[j]) { r++; } long long tmp = a[i] * a[j]; for (int k = (j - i + 1); k <= (r - l + 1); k++) { if (tmp > ans[k]) { ans[k] = tmp; } } max = a[j]; j = r + 1; } } for (int i = 1; i <= n; i++) { printf("%lld\n", ans[i]); } } return 0; }