zoukankan      html  css  js  c++  java
  • D. Yet Another Yet Another Task (ST表模版 + 单调队列)

    题目链接:https://codeforces.com/contest/1359/problem/D

    想法:

    因为是减去最大值,我们可以考虑直接枚举最大值。

    找到左边最后一个 小于等于a[i] 的位置,找到右边最后一个 小于等于a[i] 的位置

    找到这样的一个子区间,然后我们利用ST表维护前缀和,找到左边前缀和最小,右边前缀和最大的这样的范围就好了。

    #pragma GCC optimize(2)
    #pragma GCC optimize(3)
    #include <algorithm>
    #include <string>
    #include <cstring>
    #include <vector>
    #include <map>
    #include <stack>
    #include <set>
    #include <queue>
    #include <cmath>
    #include <cstdio>
    #include <iomanip>
    #include <ctime>
    #include <bitset>
    #include <cmath>
    #include <sstream>
    #include <iostream>
    
    #define ll long long
    #define ls nod<<1
    #define rs (nod<<1)+1
    #define pii pair<int,int>
    #define mp make_pair
    #define pb push_back
    #define INF 0x3f3f3f3f3f3f3f3f
    #define max(a, b) (a>b?a:b)
    #define min(a, b) (a<b?a:b)
    
    
    const double eps = 1e-10;
    const int maxn = 2e5 + 10;
    const int MOD = 998244353;
    
    int sgn(double a) { return a < -eps ? -1 : a < eps ? 0 : 1; }
    
    using namespace std;
    
    
    int a[maxn];
    int q[maxn];
    int f1[maxn],f2[maxn];
    
    
    int pre[maxn],maxx[maxn][20],minn[maxn][20];
    void rmq(int n)
    {
        for(int i=0;i<=n;i++) minn[i][0]=maxx[i][0]=pre[i];
        for(int j=1;(1<<j)<=n;j++)
        {
            for(int i=0;i+j-1<=n;i++)
            {
                maxx[i][j]=max(maxx[i][j-1],maxx[i+(1<<(j-1))][j-1]);
                minn[i][j]=min(minn[i][j-1],minn[i+(1<<(j-1))][j-1]);
            }
        }
    }
    int q1(int l,int r)
    {
        int k=0,dis=r-l+1;
        while((1<<(k+1))<=dis) ++k;
        return max(maxx[l][k],maxx[r-(1<<k)+1][k]);
    }
    int q2(int l,int r)
    {
        int k=0,dis=r-l+1;
        while((1<<(k+1))<=dis) ++k;
        return min(minn[l][k],minn[r-(1<<k)+1][k]);
    }
    
    
    int main() {
        int n;
        scanf("%d",&n);
        for (int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
            pre[i] = pre[i-1] + a[i];
        }
        rmq(n);
        int cnt;
    
        // 右边第一个 > a[i] 的数的位置
        q[1] = n + 1;
        cnt = 1;
        a[n + 1] = INF;
        for (int i = n; i >= 1; i--) {
            while (cnt && a[q[cnt]] <= a[i])
                cnt--;
            f1[i] = q[cnt] - 1;
            q[++cnt] = i;
        }
        // 左边第一个 > a[i] 的数的位置
        q[1] = 0;
        cnt = 1;
        a[0] = INF;
        for (int i = 1;i <= n;i++) {
            while (cnt && a[q[cnt]] <= a[i])
                cnt--;
            f2[i] = q[cnt];
            q[++cnt] = i;
        }
    //    for (int i = 1;i <= n;i++) {
    //        cout << f2[i] << " ";
    //    }
    //    cout << endl;
        int ans = 0;
        for (int i = 1;i <= n;i++) {
            int l = f2[i],r = f1[i];
            int maxl = q2(l,i-1);
            int maxr = q1(i,r);
            ans = max(ans,maxr - maxl - a[i]);
        }
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    git 常用命令
    svn常用命令
    mysql的bin或者sbin目录可执行文件
    SQL 函数
    SQL 通配符
    从一个Activity打开另外一个Activity
    断点下载数据
    多线程下载文件
    向服务器发送post请求
    android 查看网络图片
  • 原文地址:https://www.cnblogs.com/-Ackerman/p/13200363.html
Copyright © 2011-2022 走看看