POJ 2796 (前缀数组或者单调栈)

来源:互联网 发布:天刀男性捏脸数据 编辑:程序博客网 时间:2024/05/18 11:25

POJ 2796
题意:

给出一个数组,求出某一个数字和其所在的区间和的乘积最大值,输出最大值和左右区间的边界。其区间的定义是比这个数字大的区间。

思路:

正常的思路是枚举求出每一个数字的区间,然后算出乘积。问题是如何减少复杂度。
这里可以用数组的前缀和。左右区间的话也可以加速比较。
比如左区间:a[i] <= a[l[i]-1],那么l[i] = l[l[i]-1];

#include <iostream>#include <cstdio>using namespace std;const int maxn = 100005;int n;__int64  a[maxn],sum[maxn],l[maxn],r[maxn];int main(){    //freopen("in.txt","r",stdin);    scanf("%d",&n);    a[0] = -1;    a[n+1] = -1;    for(int i = 1;i <= n; i++) {        scanf("%I64d",&a[i]);        sum[i] = sum[i-1] + a[i];        l[i] = r[i] = i;    }    for(int i = 1;i <= n; i++) {        while(a[i] <= a[l[i]-1])            l[i] = l[l[i]-1];    }    for(int i = n;i >= 1; i--) {        while(a[i] <= a[r[i]+1]) {            r[i] = r[r[i]+1];        }    }    long long ans = -1;    int L,R;    for(int i = 1;i <= n; i++) {        long long temp = (sum[r[i]] - sum[l[i]-1])*a[i];        //printf("%I64d  %d %d \n",temp,r[i],l[i]);        if(temp > ans) {            ans = temp;            L = l[i];            R = r[i];        }    }    printf("%I64d\n%d %d\n",ans,L,R);    return 0;}
  • 还有一种方法是单调栈:

定义一个栈st,其实也可以用数组模拟栈。

1. 定义一个结构体s[maxn],s[i].m 表示下表, s[i].l左边界,s[i].r表示右边界,s[i].x 表示原来的值。2. 我们维护一个s[i].x递增的栈,从1到n开始遍历,当当前s[i].x大于st.top().x的时候s[i].l = i;3. 当小于的时候很明显st.top().r = i -1,s[i].l = st.top().l,然后栈顶出栈重复这个过程。4. 最后如果st不为空,则里面所有的结构题s[i].r = n;5. 最后依次枚举找出最大值就行。
#include <iostream>#include <cstdio>#include <stack>using namespace std;const int maxn = 100005;struct Node{    int x,l,r,m;}s[maxn];int n;stack<Node>st;long long sum[maxn];int main(){    freopen("in.txt","r",stdin);    scanf("%d",&n);    for(int i = 1;i <= n; i++) {        scanf("%d",&s[i].x);        s[i].m = i;        sum[i] = sum[i-1] + s[i].x;    }    for(int i = 1;i <= n; i++) {        s[i].l = i;        while(!st.empty() && st.top().x > s[i].x) {            s[st.top().m].r = i - 1;            s[i].l = s[st.top().m].l;            st.pop();        }        st.push(s[i]);    }    while(!st.empty()) {        s[st.top().m].r = n;        st.pop();    }    long long ans = -1;    int L,R;    for(int i = 1;i <= n; i++) {        long long temp = (sum[s[i].r] - sum[s[i].l-1])*s[i].x;        if(ans < temp) {            ans = temp;            L = s[i].l;            R = s[i].r;        }    }    printf("%I64d\n%d %d\n",ans,L,R);    return 0;}
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 埋在瓷砖下的水管漏水怎么办 水压太大把水管撑坏了怎么办 无效安装包与系统不兼容怎么办 圣空法师持五戒范戒了怎么办 美航空要是不改中国台湾标志怎么办 淘宝买的东西质量有问题怎么办 天猫618长达20天c店怎么办 新开的淘宝店铺没有生意怎么办 淘宝账号登陆限制用不了花呗怎么办 闲鱼买家签收后说是空盒怎么办 在咸鱼卖东西买家恶意退货怎么办 淘宝联系不上买家物流返回怎么办 换了支付宝绑定手机号退款怎么办啊 淘宝评价错了追评评价错了怎么办 淘宝给客户退款后还给差评怎么办 淘宝账号处于下单保护状态怎么办 淘宝卖家物流单号写错了怎么办 有个人给我发直播消息怎么办 网贷申请多了现在秒拒怎么办 顺丰快递寄的瓜果坏了怎么办 淘宝退货快递公司填错了怎么办 不小心把淘宝账号注销了怎么办 腾讯视频会员开通一个月贵怎么办 微交易买美国指数输了四千块怎么办 淘宝地址中包含了违禁词怎么办 微信支付失败但是钱扣了怎么办 支付宝向别人收款交易关闭了怎么办 从淘宝充的晋江币充值异常怎么办 接手转让店铺会员要求退卡怎么办 转转买手机卖家拒绝退款怎么办 淘宝买的东西电话号码留错了怎么办 平板电脑没电关机没保存文件怎么办 恢复出厂设置需要谷歌账号怎么办 华为手机云端里照片删除了怎么办 客户退货卖家一直没收到货怎么办 在淘宝买到假货投诉不管用怎么办 差评不接电话不回旺旺不要钱怎么办 饿了么同行恶意差评怎么办 苹果手机更新后淘宝用不了怎么办 淘宝网快递丢件了买家怎么办 评价后忘了截图五星好评怎么办