首页 > 其他分享 >感觉不错 Feel Good 和 长方形(单调栈的应用)

感觉不错 Feel Good 和 长方形(单调栈的应用)

时间:2024-03-01 23:01:02浏览次数:15  
标签:Good temp leq Feel top int se 1010 单调

感觉不错 Feel Good 和 长方形(单调栈的应用)

题目描述

给出正整数 \(n\) 和一个长度为 \(n\) 的数列 \(a\),要求找出一个子区间 \([l,r]\),使这个子区间的数字和乘上子区间中的最小值最大。

形式化的,要求找出 \([l,r]\) 使得:

\[\left(\sum \limits_{i=l}^{r}a_i\right)\times\min\limits_{i=l}^{r}a_i \]

最大。输出这个最大值与区间的两个端点。

在答案相等的情况下最小化区间长度,最小化长度的情况下最小化左端点序号。

数据范围

\(1 \leq n \leq 10^5, 0 \leq a_i \leq 10^6\)。

解法

想到单调栈可以求一个元素作为极值的最大区间,那么我们用单调栈处理出对于每一个元素,它作为最小值的最左边和最右边。处理完毕后做一遍前缀和,然后遍历每个元素,\(O(1)\)查询答案取\(max\)即可。

感觉到这题典中典,同时要注意单调栈这玩意在计算几何中好像很常用。

代码实现

int n;
void solve(){
    vector<int>a(n+1);
    vector<int>l(n+1);vector<int>r(n+1);
    stack<pair<int,pii>>t;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        int lt=i;
        while(!t.empty()&&t.top().fi>a[i]){
            auto temp=t.top();
            t.pop();
            r[temp.se.fi]=i-1;
            lt=temp.se.se;
        }
        l[i]=lt;
        t.push({a[i],{i,lt}});
    }
    while(!t.empty()){
            auto temp=t.top();
            t.pop();
            r[temp.se.fi]=n;
    }
    vector<int>s(n+1);
    for(int i=1;i<=n;i++)s[i]=a[i]+s[i-1];
    ll ans=0,ansl=1,ansr=1;
    for(int i=1;i<=n;i++){
        ll temp=1ll*a[i]*(s[r[i]]-s[l[i]-1]);
        if(temp>ans){
            ans=temp;ansl=l[i];ansr=r[i];
        }
        else if(temp==ans&&ansr-ansl>r[i]-l[i]){
            ans=temp;ansl=l[i];ansr=r[i];
        }
        else if(temp==ans&&ansr+l[i]==ansl+r[i]&&ansl>l[i]){
            ans=temp;ansl=l[i];ansr=r[i];
        }
    }
    cout<<ans<<"\n";
    cout<<ansl<<" "<<ansr<<"\n";
}

然后我们看下一题

长方形

题目描述

小明今天突发奇想,想从一张用过的纸中剪出一个长方形。

为了简化问题,小明做出如下规定:

(1)这张纸的长宽分别为 \(n,m\)。小明将这张纸看成是由\(n\times m\)个格子组成,在剪的时候,只能沿着格子的边缘剪。

(2)这张纸有些地方小明以前在上面画过,剪出来的长方形不能含有以前画过的地方。

(3)剪出来的长方形的大小没有限制。

小明看着这张纸,想了好多种剪的方法,可是到底有几种呢?小明数不过来,你能帮帮他吗?

数据范围

\(1\leq n\leq 1000,1\leq m\leq 1000\)

解法

我们首先处理出对于每一个格子,以它为低,向上连续最多有多少个没有画过的地方,记为h,然后用单调栈,去处理其作为最大值的区间右端点,和其作为唯一最大值的区间左端点。

这里为什么不能像上一道题一样直接算呢?因为其计算的是数量,而不是最大长方形面积。

为什么对于左端点要求其为唯一最大值呢?如果不唯一的话,当出现连续的相同数h时,必然会算重。

处理完这些后,累加左边长度乘右边长度乘高度,即为答案。

之前看到这个解法后,真心不知道咋做出来的。后来了解到这其实就是一种叫悬线法的trick。

代码实现

int op[1010][1010];
int h[1010][1010];
int l[1010][1010];
int r[1010][1010];
void solve(){
    int n,m;cin>>n>>m;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            char c;cin>>c;
            op[i][j]=(c=='.');
        }
    }
    for(int i=1;i<=m;i++){
        int last=0;
        for(int j=1;j<=n;j++){
            if(op[j][i])h[j][i]=j-last;
            else last=j;
        }
    }
    for(int k=1;k<=n;k++){
        stack<pii>t;
        for(int i=1;i<=m;i++){
            while(!t.empty()&&t.top().fi>h[k][i]){
                r[k][t.top().se]=i-1;
                t.pop();
            }
            t.push({h[k][i],i});
        }
        while(!t.empty()){
            r[k][t.top().se]=m;
            t.pop();
        }
    }
    for(int k=1;k<=n;k++){
        stack<pii>t;
        for(int i=m;i>=1;i--){
            while(!t.empty()&&t.top().fi>=h[k][i]){
                l[k][t.top().se]=i+1;
                t.pop();
            }
            t.push({h[k][i],i});
        }
        while(!t.empty()){
            l[k][t.top().se]=1;
            t.pop();
        }
    }
    ll ans=0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            ans+=h[i][j]*(r[i][j]-j+1)*(j-l[i][j]+1);
        }
    }
    cout<<ans<<"\n";
}

标签:Good,temp,leq,Feel,top,int,se,1010,单调
From: https://www.cnblogs.com/shi5/p/18045614

相关文章

  • CCPC2023深圳 K-四国军棋(线段树维护单调栈哈希值)
    传送门解题思路对于每个人的棋子,总是最高的那个棋子发挥决定性作用,被消耗后,再看剩下的最高的棋子。这就相当于单调不递增栈的维护过程。最后就要比较两个人的单调不递增栈是否完全相同。和经典的楼房重建相似,但是这个题不止需要维护单调栈的长度,还要维护哈希值。我是分开写的......
  • 单调队列学习笔记
    WhatIsMonotonicQueue单调队列是一种特殊的队列数据结构,用于维护一定的单调性,通常是单调递增或单调递减。单调队列的主要特点是,队列中的元素满足特定的单调性要求,使得队列的头部元素(或者尾部元素,取决于具体问题)始终是当前队列中的最大(或最小)值。这种特性使得单调队列可以高效......
  • 决策单调性相关
    1.四边形不等式1.1小标题该怎么起阿考虑一个形式如下的DP:\[f_{i}=\min_{j=1}^{i}val(j,i)\]其中\(i\)满足\(1\leqi\leqn\)。设\(f_{i}\)的最优决策点为\(oper_{i}\)。1.2一些概念决策单调性:指满足\(\symbfit{oper_1\leqoper_2\leq\dots\leqoper_......
  • 单调栈的定义与应用
    定义:单调栈是一种特殊的栈结构,通常用于解决一类特定的问题,如找到数组中元素的下一个更大(或更小)元素。它的核心特性是维护栈内元素的单调性,即栈内元素按照从栈底到栈顶的顺序,要么严格递增,要么严格递减。也即:单调递增栈:从栈底到栈顶,依次递增的顺序单调递减栈:从栈底到栈顶,依次递......
  • 单调栈算法
     定义栈内元素单调按照递增(递减)顺序排列的栈。主要用于找到每一个元素左边或右边,第一个比它大或小的数时,可使用单调栈算法。时间复杂度由于每个元素最多各自进出栈一次,复杂度是O(n)功能递增单调栈:在一个队列中针对每一个元素从它右边找到第一个比它小的元素在一个......
  • 单调栈优化DP
    当有形如\(f_i=min_{j=0}^{l(i)}f_j+w转移代价\)我们就可以使用单调栈优化DP为什么不用单调队列???当有形如\(f_i=min_{j=l(i)}^{i-1}f_j+w转移代价\)我们就可以使用单调队列优化DP至于为毛,就可以从它的工作原理上去分析6305.最小值\(dp_i=min_{j=0}^{i-1}g_j+f(min_{x=j+1......
  • CF1398C Good Subarrays(写给我们萌新团体)
    GoodSubarrays传送门:GoodSubarrays-洛谷|计算机科学教育新生态(luogu.com.cn)思路暴力!!!!!一如既往的暴力!!!复杂度O(n^2)数据n到1e5TLE必定TLE我们可以用一个桶来优化实质上其实还是高中所学的排列组合思想第一步:当然是前缀和了,这边讲给新手写一下,有点冗杂,是高手直接......
  • 玉蟾宫(单调栈)
    玉蟾宫(单调栈)题目描述有一天,小猫rainbow和freda来到了湘西张家界的天门山玉蟾宫,玉蟾宫宫主蓝兔盛情地款待了它们,并赐予它们一片土地。这片土地被分成N*M个格子,每个格子里写着’R’或者’F’,R代表这块土地被赐予了rainbow,F代表这块土地被赐予了freda。现在freda要在这里......
  • Blocks(单调栈)
    Blocks题目描述给出N个正整数a[1..N],再给出一个正整数k,现在可以进行如下操作:每次选择一个大于k的正整数a[i],将a[i]减去1,选择a[i-1]或a[i+1]中的一个加上1。经过一定次数的操作后,问最大能够选出多长的一个连续子序列,使得这个子序列的每个数都不小于k。总共给出M次询问,每次询问......
  • Blocks(单调栈)
    题目链接因为可以操作无限次,所以相当于只要一个区间中的所有数相加的平均值大于k即成立首先,我们需要通过前缀和维护,可以在加的时候减去一个k,这样只用判断\(i>j且sum[i]-sum[j]>0\)则在[j+1,i]区间中存在满足题目的连续序列如图用红线指的是存入的<0并且单调递减的前缀和su......