题目:小C的数学问题
参考博客:第二届全国中医药院校程序设计竞赛
思路:思路就是把a[i]作为最小值,然后去用两个指针去分别寻找a[i]左侧比a[i]小的那个位置的后一个位置以及右侧比a[i]大的那个位置的前一个位置。然后我就开始根据这个思路去求解问题,但是没有进行优化直接进行的,时间超时。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100005;
#define LL long long
int a[maxn];
LL sum[maxn];
int main()
{
int n;
scanf("%d", &n);
sum[0] = 0;
for(int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
sum[i] += sum[i-1]+a[i];//前缀和
}
int l, r, L, R;
LL ma = 0;
for(int i = 1; i <= n; i++)
{
l = r = i;
while(a[r+1] >= na[i] && r <= n)r++;//右侧比a[i]大的数
while(a[l-1] >= a[i] && l > 1)l--;//左侧比a[i]小的数
LL ans = (sum[r] - sum[l-1])*a[i];//求和
if(ans > ma)
{
ma = ans;
L = l;
R = r;
}
}
printf("%lld\n", ma);
printf("%d %d\n", L, R);
return 0;
}
后来优化查找左边比a[i]小的那个位置,右边比a[i]大的那个位置,通过set来维护。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100005;
#define LL long long
LL sum[maxn];
struct Node
{
int x, id;
} a[maxn];
set<LL>s1, s2;//s1用来存取左侧,s2用来存取右侧。
set<LL>::iterator it;
bool cmp(Node A, Node B)
{
return A.x < B.x;
}
int main()
{
int n;
scanf("%d", &n);
sum[0] = 0;
for(int i = 1; i <= n; i++)
{
scanf("%d", &a[i].x);
a[i].id = i;
sum[i] = sum[i-1]+a[i].x;//前缀和
}
int l, r, L, R;
LL ma = -1;
int i = 1;
s1.clear();
s2.clear();
s1.insert(n+1);
s2.insert(n+1);
sort(a+1, a+1+n, cmp);//排序
while(i <= n)
{
l = r = i;
while(a[l].x == a[r+1].x && r <= n )r++;//找到同一个数
for(int j = l; j <= r; j++)
{
int t1, t2;
it = s1.lower_bound(n+1-a[j].id);//寻找此时比a[j]小的数,为什么这么做?
//因为set里面存的是比a[j]小的数的位置。
t1 = n+1-*it; //还原真实位置 //为什么n+1-a[j].id?因为这么做会筛选出左侧比a[i]小的距离a[i]最近的一个数
it = s2.lower_bound(a[j].id);
t2 = *it;
LL ans = (sum[t2-1]-sum[t1])*a[j].x;
if(ans > ma)
{
ma = ans;
L = t1+1;
R = t2-1;
}
}
for(int j = l; j <= r; j++)
{
s1.insert(n+1-a[j].id);
s2.insert(a[j].id);
}
i = r+1;
}
printf("%lld\n", ma);
printf("%d %d\n", L, R);
return 0;
}
单调栈实现:
代码:
#include<string.h>
#include<stdio.h>
#include<iostream>
#include<stack>
using namespace std;
const int maxn = 100005;
#define LL long long
stack<int>s;
int a[maxn];
LL sum[maxn];
int main()
{
int n;
scanf("%d", &n);
sum[0] = 0;
while(!s.empty())s.pop();
for(int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
sum[i] = sum[i-1]+a[i];
}
a[n+1] = -1;
int l, r;
LL ma = 0;
for(int i = 1; i <= n+1; i++)
{
if(s.empty() || a[i] >= a[s.top()])s.push(i);
else
{
int top;
while(!s.empty() && a[i] < a[s.top()])
{
top = s.top();
s.pop();
LL tmp = sum[i-1]-sum[top-1];
tmp *= a[top];
if(tmp >= ma)
{
ma = tmp;
r = i-1;
l = top;
//cout<<"hell"<<l<<" "<<r<<endl;
}
}
// s.push(i);
//cout<<top<<endl;
s.push(top); //将最后一次出栈的栈顶元素入栈
a[top]=a[i];
}
}
printf("%lld\n",ma);
printf("%d %d\n",l, r);
return 0;
}