• 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;
    }
  • 相关阅读:
    复合词 (Compund Word,UVa 10391)
    卡片游戏 (Throwing card away I,UVa10935)
    交换学生 (Foreign Exchange,UVa10763)
    Ducci序列 (Ducci Sequence,ACM/ICPC Seoul 2009,UVa1594)
    代码对齐 (Alignment of Code,ACM/ICPC NEERC 2010,UVa1593)
    打印队列 (Printer Queue,ACM/ICPC NWERC 2006,UVA12100)
    更新字典 (Updating a Dictionary,UVa12504)
    golang 定时弹出对话框
    重新梳理一下adb操作app(golang版)
    通过无线网络使用ADB ( Connect to android with ADB over TCP )
  • 原文地址:https://www.cnblogs.com/-Ackerman/p/13200363.html
Copyright © 2020-2023  润新知