zoukankan      html  css  js  c++  java
  • poj2796(单调栈+树状数组)

    Feel Good

    题意:

      给定一个区间,要求找出一个子区间使得这个区间的最小值乘以区间上所有数的和最大,输出和,与这个区间的左右边界。

    分析:

      很明显这个最优子区间的最小值,一定是总区间上的某个值。所以我们就枚举每个值,利用单调栈找到每个值对应的子区间的边界,在用树状数组求出这个子区间所有数的和,取n次结果中的最大值即可。

      做这个题之前可以先看一下单调栈树状数组的裸题。

    代码:

    #include <stack>
    #include <stdio.h>
    #include <string.h>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    #define ll long long
    #define ull unsigned long long
    #define cls(x) memset(x,0,sizeof(x))
    #define clslow(x) memset(x,-1,sizeof(x))
    
    const int maxn=1e5+100;
    
    int n;
    
    stack<int>st;
    ll bit[maxn];
    int a[maxn],L[maxn],R[maxn];
    
    int lowbit(int x)
    {
        return x&-x;
    }
    
    void update(int x,int add)
    {
        while(x<=n)
        {
            bit[x]+=add;
            x+=lowbit(x);
        }
    }
    
    ll sum(int x)
    {
        ll res=0;
        while(x>0)
        {
            res+=bit[x];
            x-=lowbit(x);
        }
        return res;
    }
    
    //树状数组求区间和
    ll query(int x,int y)
    {
        return sum(y)-sum(x-1);
    }
    
    //单调栈找出每个值对应的子区间的边界
    void solve()
    {
        while(!st.empty())  st.pop();
        for(int i=1;i<=n;i++){
            while(st.size()&&a[st.top()]>=a[i]) st.pop();
    
            if(st.empty())  L[i]=0;
            else            L[i]=st.top();
    
            st.push(i);
        }
        while(!st.empty())  st.pop();
        for(int i=n;i>=1;i--){
            while(st.size()&&a[st.top()]>=a[i]) st.pop();
    
            if(st.empty())  R[i]=n+1;
            else            R[i]=st.top();
    
            st.push(i);
        }
    }
    
    void print()
    {
        int l,r;
        ll ans=-1;
        for(int i=1;i<=n;i++){
            ll val=query(L[i]+1,R[i]-1)*a[i];
            if(ans<val){
                ans=val;
                l=L[i]+1;
                r=R[i]-1;
            }
        }
        printf("%lld
    ",ans);
        printf("%d %d
    ",l,r);
    }
    
    int main()
    {
    //    freopen("in.txt","r",stdin);
        while(scanf("%d",&n)!=EOF)
        {
            cls(bit);
            for(int i=1;i<=n;i++){
                scanf("%d",&a[i]);
                update(i,a[i]);
            }
    
            solve();
            print();
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Javascript 返回上一页
    html中link和import方式导入CSS文件的区别
    Leecode no.76 最小覆盖子串
    Leecode no.344 反转字符串
    Leecode no.167 两数之和 II 输入有序数组
    Leecode no.567 字符串的排列
    遍历目录和文件信息
    JAVASCRIPT显示农历的日历
    asp.net上传图片加水印(c#)
    asp.net XML操作类
  • 原文地址:https://www.cnblogs.com/shutdown113/p/9381378.html
Copyright © 2011-2022 走看看