51nod 1215 数组的宽度&poj 2796 Feel Good(单调栈)

  单调栈求每个数在哪些区间是最值的经典操作。

  把数一个一个丢进单调栈,弹出的时候[st[top-1]+1,i-1]这段区间就是弹出的数为最值的区间。

  poj2796 弹出的时候更新答案即可

#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
#include<map>
#define ll long long
using namespace std;
const int maxn=500010,inf=1e9;
int n,top,ansl,ansr;
ll ans=-1;
int st[maxn],a[maxn];
ll sum[maxn];
void read(int &k)
{
    int f=1;k=0;char c=getchar();
    while(c<‘0‘||c>‘9‘)c==‘-‘&&(f=-1),c=getchar();
    while(c<=‘9‘&&c>=‘0‘)k=k*10+c-‘0‘,c=getchar();
    k*=f;
}
int main()
{
    read(n);
    for(int i=1;i<=n;i++)read(a[i]),sum[i]=sum[i-1]+a[i];a[++n]=-1;
    for(int i=1;i<=n;i++)
    {
        for(;top&&a[i]<=a[st[top]];top--)
        {
            ll val=1ll*a[st[top]]*(sum[i-1]-sum[st[top-1]]);
            if(val>ans)ans=val,ansl=st[top-1]+1,ansr=i-1;
        }
        st[++top]=i;
    }
    printf("%lld\n%d %d",ans,ansl,ansr);
    return 0;
}

  51nod1215 求出最大值对答案的贡献之和与最小值对答案的贡献之和相减即可。

  显然贡献为a[i]*(i-st[top])*(st1[top]-st[top-1]);

#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
#include<map>
#define ll long long
using namespace std;
const int maxn=500010,inf=1e9;
int n,top1,top2;
int a[maxn],b[maxn],st1[maxn],st2[maxn];
ll mx,mn;
void read(int &k)
{
    int f=1;k=0;char c=getchar();
    while(c<‘0‘||c>‘9‘)c==‘-‘&&(f=-1),c=getchar();
    while(c<=‘9‘&&c>=‘0‘)k=k*10+c-‘0‘,c=getchar();
    k*=f;
}
int main()
{
    read(n);
    for(int i=1;i<=n;i++)read(a[i]),b[i]=a[i];b[++n]=inf;
    for(int i=1;i<=n;i++)
    {
        for(;top1&&a[i]<=a[st1[top1]];top1--)
        mn+=1ll*a[st1[top1]]*(i-st1[top1])*(st1[top1]-st1[top1-1]);
        for(;top2&&b[i]>=b[st2[top2]];top2--)
        mx+=1ll*b[st2[top2]]*(i-st2[top2])*(st2[top2]-st2[top2-1]);
        st1[++top1]=st2[++top2]=i;
    }
    printf("%lld\n",mx-mn);
    return 0;
}

时间: 2024-10-10 22:41:19

51nod 1215 数组的宽度&poj 2796 Feel Good(单调栈)的相关文章

POJ 2796 Feel Good(单调栈)

题目地址:POJ 2796 单调栈的第一题就是这道..把我弄的晕头转向.现在终于明白了,对单调栈又加深了理解.原来单调栈不只是可以维护数. 代码如下: #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <stdlib.h> #include <math.h> #include <ctype.h> #incl

1215 数组的宽度

1215 数组的宽度 题目来源: Javaman 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 收藏 关注 N个整数组成的数组,定义子数组a[i]..a[j]的宽度为:max(a[i]..a[j]) - min(a[i]..a[j]),求所有子数组的宽度和. Input 第1行:1个数N,表示数组的长度.(1 <= N <= 50000) 第2 - N + 1行:每行1个数,表示数组中的元素(1 <= A[i] <= 50000) Output 输出所有子数组的

51nod 1215 单调栈/迭代

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1215 1215 数组的宽度 题目来源: Javaman 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 收藏 关注 N个整数组成的数组,定义子数组a[i]..a[j]的宽度为:max(a[i]..a[j]) - min(a[i]..a[j]),求所有子数组的宽度和. Input 第1行:1个数N,表示数组的长度.(1 <= N <=

Poj 2796 单调栈

关于单调栈的性质,和单调队列基本相同,只不过单调栈只使用数组的尾部, 类似于栈. Accepted Code: 1 /************************************************************************* 2 > File Name: 2796.cpp 3 > Author: Stomach_ache 4 > Mail: [email protected] 5 > Created Time: 2014年07月21日 星期一

POJ 3415 Common Substrings(后缀数组+单调栈)

[题目链接] http://poj.org/problem?id=3415 [题目大意] 求出两个字符串长度大于k的公共子串的数目. [题解] 首先,很容易想到O(n2)的算法,将A串和B串加拼接符相连, 做一遍后缀数组,把分别属于A和B的所有后缀匹配,LCP-k+1就是对答案的贡献, 但是在这个基础上该如何优化呢. 我们可以发现按照sa的顺序下来,每个后缀和前面的串的LCP就是区间LCP的最小值, 那么我们维护一个单调栈,将所有单调递减的LCP值合并, 保存数量和长度,对每个属于B串的后缀更新

[poj 2796]单调栈

题目链接:http://poj.org/problem?id=2796 单调栈可以O(n)得到以每个位置为最小值,向左右最多扩展到哪里. #include<cstdio> #include<algorithm> #include<stack> using namespace std; const int maxn=100005; int a[maxn]; int l[maxn]; int r[maxn]; long long pre[maxn]; stack< p

Feel Good (poj 2796)

题目大意就是在给出的串中找出一段连续数字,使得 这一段的和 乘上 这一段最小的数 的结果最大. 可以用rmq做.每次区间找当中最小的数,算出值并记录位置.然后再递推它的左右区间. 不过- -,一开始用深搜递推RE了.栈空间不够了,然后慢慢优化,最后还是ac了. 貌似这一题是用单调栈做的,还可以用查并集做...我也是醉了 具体看代码吧 1 /************************************************************************* 2 > F

数组的宽度 单调栈

N个整数组成的数组,定义子数组a[i]..a[j]的宽度为:max(a[i]..a[j]) - min(a[i]..a[j]),求所有子数组的宽度和. 分析: 我们只要统计每个数做为最小的数和最大的数所在区间有多少个.这样求当前数作为最大的数左右范围,这个用单调栈维护下,同理最小的也是然后左区间大小乘右区间大小就是这个数作为最大的出现的区间数: 以1 5 4 2 3为例,逐个入栈计算每个数的右边界: 1入栈 => 1 5入栈,前面所有比5小的出栈,并将右边界设为5 => 5 (确定了1的右边界

POJ 3415:后缀数组+单调栈优化

题意很简单,求两个字符串长度大于等于K的子串个数 一开始还是只会暴力..发现n^2根本没法做...看了题解理解了半天才弄出来,太弱了... 思路:把两个字符串连接后做一次后缀数组,求出height 暴力的想法自然是枚举第一个子串的起始位置i和第二个子串的起始位置j,肯定会T的 看了题解才知道有单调栈这种有优化方法.. 将后缀分为A组(起始点为第一个字符串).B组 设符合要求的lcp长度为a,则其对答案的贡献为a-k+1(长度为k~a的都是符合要求的) 一开始这里我也是有疑问的,比如说k=1,aa