• P2422 良好的感觉(两头单调)


    描述:https://www.luogu.com.cn/problem/P2422

    kkk做了一个人体感觉分析器。每一天,人都有一个感受值Ai,Ai越大,表示人感觉越舒适。在一段时间[i, j]内,人的舒适程度定义为[i, j]中最不舒服的那一天的感受值 * [i, j]中每一天感受值的和。现在给出kkk在连续N天中的感受值,请问,在哪一段时间,kkk感觉最舒适?


    先考虑暴力。

    怎么暴力?我会枚举区间左右端点

    光是枚举左右端点就已经T飞了

    我们考虑最小值有多少种情况?

    没错,是n种,每个数都可能是最小值。

    如果把某个数当成区间最小值的话,那么在保证最小的前提下,区间越大越好

    但是问题来了。区间和可以用前缀和优化,那怎么定区间呢?

    说白了,我们想找到这个数左边第一个更小的数记作L和右边第一个更小的数记作R

    怎么办?单调队列

    当压入一个数的时候,会弹出一些更小的数,那么其实弹出的那些数的R值就是本数

    同样,当无法从队列里弹出数的时候,那么本数的L值就是那个在队列尾的数

    至于一个数的右边或者左边没有更小的数时,我们认为把它们设置为下标为0,n+1

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    ll n;
    ll a[100009],q[100009],p[100009];
    ll l[100009],r[100009],sumn[100009];
    int main()
    {
        cin>>n;
        ll tail=0,head=1;
        for(int i=1;i<=n;i++)
        {
            scanf("%ld",&a[i]);
            sumn[i]=sumn[i-1]+a[i];
            while(tail>=head&&a[i]<q[tail])
            {
                //a[i]是被踢掉元素右边的第一个更小的元素
                r[p[tail]]=i; 
                tail--;
            }
            l[i]=p[tail];//踢到不能踢为止,那个踢不动的就是左边第一个更小的元素 
            q[++tail]=a[i],p[tail]=i;
        }
        sumn[n+1]=sumn[n]; 
        for(int i=1;i<=n;i++)
        {
            if(l[i]==0)    l[i]=0;
            if(r[i]==0)    r[i]=n+1;
        }
        ll ans=0;
        for(int i=1;i<=n;i++)
        ans=max(ans,a[i]*(sumn[r[i]-1]-sumn[l[i]]));
        cout<<ans;
    }
  • 相关阅读:
    java getEnv不区分大小写 getProperty区分大小写
    spring 解析配置文件问题
    (转载)Java里快如闪电的线程间通讯
    quartz中关键类
    HTTP中缓存相关
    (转载)javascript函数作用域和提前声明
    (转载)ETL利器Kettle实战应用解析系列一【Kettle使用介绍】
    rcnn 理解笔记
    打乱图片顺序,按一定比例分别存放
    Python 批量读取文件夹下的图片,并保存在文档下
  • 原文地址:https://www.cnblogs.com/iss-ue/p/12531554.html
Copyright © 2020-2023  润新知