• [POJ2796]Feel Good


      题目传送门:http://poj.org/problem?id=2796

      这道题的话我用了RMQ和二分。

      思想:用minm来表示区间[L,R]的最小值,很明显一个区间[L,R]能取得的最大值,要么就是[L,minm-1],要么就是[minm+1,R],还有就是整个区间的和乘最小值。

      因为对于某两个最小值相等的区间来说(题目说明是非负整数),显然越大的区间取得的最大值越大。

        

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    using namespace std;
    const int maxn=100010;
    int num[maxn],n,sum[maxn],fmin[maxn][20],fmax[maxn][20];
    long long ans=0,ansl,ansr;
    
    int querymin(int l,int r)
    {
        int k=0;
        if (l>r)return 0;
        while (1<<(k+1)<=r-l+1)k++;
        return min(fmin[l][k],fmin[r-(1<<k)+1][k]);
    }
    
    int querymax(int l,int r)
    {
        int k=0,tmp=0;
        if (l>r)return 0;
        while (1<<(k+1)<=r-l+1)k++;
        tmp=max(fmax[l][k],fmax[r-(1<<k)+1][k]);
        tmp=max(tmp,(sum[r]-sum[l-1])*querymin(l,r));
        if (tmp>ans)
        {
           ans=tmp;
           ansl=l;
           ansr=r;
        }
        return tmp;
    }
    
    void findmin()                                          //用RMQ求第i个到第j个这个区间的最小值是哪一个
    {
         int i,j;
         memset(fmin,0x7f,sizeof(fmin));
         for (i=1;i<=n;i++)fmin[i][0]=i;
         for (j=1;(1<<j)<=n;j++)
             for (i=1;i+(1<<j)-1<=n;i++)
                 if (num[fmin[i][j-1]]<num[fmin[i+(1<<(j-1))][j-1]])fmin[i][j]=fmin[i][j-1];
                    else fmin[i][j]=fmin[i+(1<<(j-1))][j-1]; 
    }
    
    void findmax()                                           //表示求第i个到第j个这个区间能取得的最大值
    {
         int i,j,l,r;
         memset(fmax,0,sizeof(fmax));
         for (i=1;i<=n;i++)fmax[i][0]=num[i]*num[i];
         for (j=1;(1<<j)<=n;j++)
             for (i=1;i+(1<<j)-1<=n;i++)
             {
                 r=i+(1<<j)-1;
                 l=querymin(i,r);
                 fmax[i][j]=max(querymax(i,max(i,l-1)),querymax(max(l+1,r),r));
                 fmax[i][j]=max(fmax[i][j],(sum[r]-sum[i-1])*num[l]);
                 if (fmax[i][j]>ans)
                 {
                    ans=fmax[i][j];
                    ansl=i;
                    ansr=r;
                 }
             }
    }
    
    int main()
    {
        int i,j;
        scanf("%d",&n);
        sum[0]=0;
        for (i=1;i<=n;i++)
        {
            scanf("%d",&num[i]);
            sum[i]=sum[i-1]+num[i];
        }
        findmin();
        findmax();
        cout<<ans<<endl<<ansl<<" "<<ansr<<endl;
        return 0;
    }
  • 相关阅读:
    微软紧急安全公告:当心SQL攻击爆发
    婴儿
    感冒了
    System.IO.FileAttributes
    mssql数据库,无法用语句实现“强制还原”功能
    好大的风
    无聊的游戏
    JZOJ 4276【NOIP2015模拟10.28A组】递推
    JZOJ 4289.Mancity
    单词检索(search)
  • 原文地址:https://www.cnblogs.com/Sun-Sea/p/5236834.html
Copyright © 2020-2023  润新知