小C的数学问题

题目描述

小C是个云南中医学院的大一新生,在某个星期二,他的高数老师扔给了他一个问题。

让他在1天的时间内给出答案。

但是小C不会这问题,现在他来请教你。

请你帮他解决这个问题。

有n个数,每个数有权值。

数学老师定义了区间价值为区间和乘上区间内的最小值。

现在要你找出有最大区间价值的区间是什么,并输出区间价值。

输入

每个输入文件只包含单组数据。
第一行一个整数n。(1 <= n <= 100000)
第二行n个整数a_1,a_2,…,a_n。(0 <= a_i <= 1000000)

输出

第一行输出一个整数,表示最大的区间价值。
第二行输出两个整数,表示区间的起点和终点。
保证答案唯一。

样例输入
复制样例数据 6
10 1 9 4 5 9

样例输出
108
3 6

以下代码包含:一个数为一个区间最小值,求这个区间的左右端点的方法,使用记忆化优化,值得学习

int main()
{
    int n;cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        sum[i]=sum[i-1]+a[i];///注意别写错了
    }
    for(int i=1;i<=n;i++)///左区间要从最左边的数开始判断
    {
        int j=i;
        while(j>1&&a[j-1]>=a[i])  j=l[j-1];///j>1,因为a[1]的左端点一定时它本身1,所以j!=1
        ///若a[j-1]>=a[i],那么a[j-1]的左区间端点l[j-1]那个数a[l[j-1]]的值也一定比a[i]大,所以j=l[j-1],
        ///再继续判断第j个数的左边那个数a[j-1]是否比a[i]大,重复以上操作,循环下去
        l[i]=j;///直到j=1或a[j-1]<a[i]跳出循环
    }
    for(int i=n;i>=1;i--)///右区间要从最右边的数开始判断
    {
        int j=i;
        while(j<n&&a[i]<=a[j+1]) j=r[j+1];
        r[i]=j;
    }
    long long ans=-1;int L=0,R=0;long long maxn=0;
    ///ans要初始化为-1,因为有区间为0的情况
    for(int i=1;i<=n;i++)
    {
        maxn=(sum[r[i]]-sum[l[i]-1])*a[i];
        if(maxn>ans)
        {
            ans=maxn;
            L=l[i],R=r[i];
        }
    }
    cout<<ans<<endl;cout<<L<<" "<<R<<endl;
}

参考博客:https://blog.csdn.net/renzijing/article/details/89024366(感谢大佬)

猜你喜欢

转载自blog.csdn.net/Spidy_harker/article/details/89084346