题目链接:https://ac.nowcoder.com/acm/contest/884/C
链接:https://ac.nowcoder.com/acm/contest/884/C
来源:牛客网
时间限制:C/C++ 3秒,其他语言6秒
空间限制:C/C++ 524288K,其他语言1048576K
64bit IO Format: %lld
题目描述
Your are given two sequences a1…na_{1 \dots n}a1…n and b1…nb_{1 \dots n}b1…n .You need to answer max1≤l≤r≤n{min(al…r)×sum(bl…r)}\displaystyle \max_{1 \le l \le r \le n} \{min(a_{l \dots r}) \times sum(b_{l \dots r})\}1≤l≤r≤nmax{min(al…r)×sum(bl…r)} 。
Where min(a) means the minimal value of every element of sequence a, sum(a) means the sum of every element of sequence a .
输入描述:
The first line contains an integer n . The second line contains n integers meaning a1…na_{1 \dots n}a1…n . The third line contains n integers meaning b1…nb_{1 \dots n}b1…n .
输出描述:
An integer meaning the answer.
示例1
输入
复制
3 1 -1 1 1 2 3
输出
复制
3
备注:
For all test datas, 1≤n≤3×106,−106≤ai,bi≤1061 \leq n \leq 3 \times 10^6,-10^6 \leq a_i,b_i \leq 10^61≤n≤3×106,−106≤ai,bi≤106.
思路:
对于a数组中的每一个数a[i],它作为最小值的作用空间为左边第一个小于他的数,到右边第一个小于他的数
所以可以用单调栈维护左右两边第一个小于他的数
对于第二个序列,用线段数维护区间前缀和的最大最小值,当一个区间的a[i]一定时,就可以在b[i]的区间前缀和中寻找最大值最小值,如果a[i]大于0,则在i到右边第一个小于它的数 之间寻找最大的前缀和,在左边第一个小于他的数到i寻找最小的前缀和,两者相减;如果a[i]小于0,则情况相反,用最小值减去最大值即可。
(比赛可以过,测评机不稳定赛后就T了)
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
#include <vector>
#include <cmath>
#include <stack>
//#define int long long
using namespace std;
typedef long long ll;
const int maxn = 3e6 + 10;
const ll INF = 0x3f3f3f3f3f3f;
int a[maxn];
int b[maxn];
struct Node {
int l, r;
ll maxx;
ll minn;
}Tree[maxn<<2];
void Build(int root, int l, int r) {
Tree[root].l = l, Tree[root].r = r;
Tree[root].maxx = Tree[root].minn = 0;
if (l == r)return;
int mid = (l + r) >> 1;
Build(root << 1, l, mid);
Build(root << 1 | 1, mid + 1, r);
}
void pushup(int root) {
Tree[root].maxx = max(Tree[root << 1].maxx, Tree[root << 1 | 1].maxx);
Tree[root].minn = min(Tree[root << 1].minn, Tree[root << 1 | 1].minn);
}
void Insert(int root, int pos, ll val) {
if (Tree[root].l == Tree[root].r) {
Tree[root].maxx = val;
Tree[root].minn = val;
return;
}
int mid = (Tree[root].l + Tree[root].r) >> 1;
if (pos <= mid) {
Insert(root << 1, pos, val);
}
else {
Insert(root << 1 | 1, pos, val);
}
pushup(root);
}
ll query(int root, int l, int r, int op) {
if (Tree[root].l >= l && Tree[root].r <= r) {
return op == 0 ? Tree[root].maxx : Tree[root].minn;
}
int mid = (Tree[root].l + Tree[root].r) >> 1;
ll maxx = -INF, minn = INF;
if (l <= mid) {
if (op == 0) {
maxx = max(maxx, query(root << 1, l, r, op));
}
else {
minn = min(minn, query(root << 1, l, r, op));
}
}
if (r > mid) {
if (op == 0) {
maxx = max(maxx, query(root << 1 | 1, l, r, op));
}
else {
minn = min(minn, query(root << 1 | 1, l, r, op));
}
}
return op == 0 ? maxx : minn;
}
int st[maxn][2];
ll sum[maxn];
int n;
queue<int>q;
stack<int>s;
signed main() {
ios::sync_with_stdio(false), cin.tie(NULL), cout.tie(NULL);
cin >> n;
for (int i = 1; i <= n; ++i)cin >> a[i];
sum[0] = 0;
for (int i = 1; i <= n; ++i) { cin >> b[i]; sum[i] = sum[i - 1] + b[i]; }
for (int i = 1; i <= n; ++i)
{
while (!s.empty() && a[s.top()] > a[i]) {
int inx = a[s.top()];
while (!s.empty() && a[s.top()] == inx) {
//cerr << "debug " << endl;
q.push(s.top());
s.pop();
}
while (!q.empty()) {
st[q.front()][1] = i;
//cerr << "emmm "<<i << endl;
q.pop();
}
}
st[i][0] = s.empty() ? 0 : s.top();
s.push(i);
}
while (!s.empty()) {
st[s.top()][1] = n + 1;
s.pop();
}
Build(1, 0, n);
for (int i = 0; i <= n; i++) {
Insert(1, i, sum[i]);
}
ll ans = -INF;
for (int i = 1; i <= n; i++) {
if (a[i] >= 0) {
ans = max(ans, (query(1, i, st[i][1] - 1, 0) - query(1, st[i][0], i, 1))*a[i]);
}
else {
ans = max(ans, (query(1, i, st[i][1] - 1, 1) - query(1, st[i][0], i, 0))*a[i]);
}
}
cout << ans << endl;
//system("pause");
return 0;
}