首页 > 其他分享 >[题解]CF1473D Program

[题解]CF1473D Program

时间:2024-06-24 12:34:57浏览次数:27  
标签:CF1473D int 题解 ST Program inf 极值

思路

因为此题目中对于数的更新只能为 \(1\),所以,如果我们找到了 \([1,l - 1]\) 与 \([r + 1,n]\) 中能获得的两个极值即可。

我们为 \(S\) 赋予权值,用一个数组 \(a\) 储存:

  1. 如果 \(S_i\) 为 +,则其权值为 \(1\)。
  2. 否则其权值为 \(-1\)。

那么,在第 \(i\) 次操作后,能产生的数是 \(\sum_{j = 1}^ia_j\)。

考虑用前缀和维护这个数,记作 \(s\)。

因为它是一个静态的问题,所以用 ST 表维护一下前缀和的极值。

对于前一部分(即 \([1,l - 1]\)),只需要求出 \(\max_{i \in [1,l - 1]}\{s_i\}\) 与 \(\min_{i \in [1,l - 1]}\{s_i\}\);对于后一部分,只需要求出 \(\max_{i \in [r + 1,n]}\{s_i\} - s_r + s_{l - 1}\) 与 \(\min_{i \in [r + 1,n]}\{s_i\} - s_r + s_{l - 1}\) 即可。(因为 \([l,r]\) 区间被忽略了)

此外,需要注意的是,如果 \(0\) 未包含在两个极值之间,需要将答案额外加上 \(1\)。

Code

#include <bits/stdc++.h>  
#define re register  
  
using namespace std;  
  
const int N = 2e5 + 10,M = 25,inf = 0x3f3f3f3f;  
int T,n,q;  
int arr[N],lg[N + 10];  
string s;  
  
struct ST{  
    #define pot(x) (1 << x)  
  
    int dp1[N][M],dp2[N][M];//dp1 维护最小值,dp2 维护最大值   
  
    inline void init(){  
        for (re int j = 1;j <= lg[n];j++){  
            for (re int i = 1;i <= n - pot(j) + 1;i++){  
                dp1[i][j] = min(dp1[i][j - 1],dp1[i + pot(j - 1)][j - 1]);  
                dp2[i][j] = max(dp2[i][j - 1],dp2[i + pot(j - 1)][j - 1]);  
            }  
        }  
    }  
  
    inline int query_Min(int l,int r){  
        int x = lg[r - l + 1];  
        return min(dp1[l][x],dp1[r - pot(x) + 1][x]);  
    }  
  
    inline int query_Max(int l,int r){  
        int x = lg[r - l + 1];  
        return max(dp2[l][x],dp2[r - pot(x) + 1][x]);  
    }  
  
    #undef pot  
}st;  
  
inline void Log(){  
    lg[1] = 0;  
    for (re int i = 2;i <= N;i++) lg[i] = lg[i / 2] + 1;  
}  
  
inline int sum(int l,int r){  
    return arr[r] - arr[l - 1];  
}  
  
int main(){  
    ios::sync_with_stdio(0);  
    cin.tie(0);  
    cout.tie(0);  
    cin >> T;  
    Log();  
    while (T--){  
        cin >> n >> q >> s;  
        s = ' ' + s;  
        for (re int i = 1;i <= n;i++){//转化权值   
            if (s[i] == '+') arr[i] = arr[i - 1] + 1;  
            else arr[i] = arr[i - 1] - 1;  
        }  
        for (re int i = 1;i <= n;i++) st.dp1[i][0] = st.dp2[i][0] = arr[i];  
        st.init();  
        while (q--){  
            int l,r;  
            cin >> l >> r;  
            int l1 = 1,r1 = l - 1;  
            int l2 = r + 1,r2 = n;  
            int Min = inf,Max = -inf;  
            if (l1 <= r1){//避免出现 l = 1 的情况   
                Min = min(Min,st.query_Min(l1,r1));  
                Max = max(Max,st.query_Max(l1,r1));  
            }  
            if (l2 <= r2){//避免出现 r = n 的情况   
                Min = min(Min,st.query_Min(l2,r2) - sum(l,r));  
                Max = max(Max,st.query_Max(l2,r2) - sum(l,r));  
            }  
            if (Min == inf) Min = 0;//特判 l = 1 且 r = n 的情况   
            if (Max == -inf) Max = 0;  
            if (Min <= 0 && 0 <= Max) cout << (Max - Min + 1) << "\n";  
            else cout << (Max - Min + 2) << "\n";  
        }  
    }  
    return 0;  
}  

标签:CF1473D,int,题解,ST,Program,inf,极值
From: https://www.cnblogs.com/WaterSun/p/18264795

相关文章

  • [题解]CF1312E Array Shrinking
    思路本题为P3146变式,也算是一道很经典的区间DP题了。因为\(n\leq500\),考虑区间DP。定义\(dp_{i,j}\)表示操作\([i,j]\)区间剩余长度的最小值。那么,我们可以枚举一个中间值\(k\),可以显然地得到一个状态转移方程(即不能合二为一的情况):\[dp_{i,j}=\min(dp_{i,......
  • [题解]CF1223F Stack Exterminable Arrays
    CCF出的原题观摩一下。思路首先可以用一个Trie来维护。在这里对本文中的一些变量做一下说明。\(p\)表示当前维护的Trie中,指向的元素编号。\(t_i\)表示在Trie中编号为\(i\)的元素在原序列中的值。\(f_i\)表示在Trie中编号为\(i\)的元素在Trie中的父节点。......
  • [题解]CF1175E Minimal Segment Cover
    思路这是一道简单的DP题,DP题的核心就是状态转移。先来说一说\(dp\)数组的含义。\(dp_{i,j}\)表示从\(i\)这个点用\(2^j\)条线段能走到的最远的点。我们再来考虑一下边界情况。因为我们只用\(2^0\)条线段,那么:\(dp_{i,0}=\max(dp_{i,0},r)\)接着,我们递推一......
  • [题解]CF1092D1 Great Vova Wall (Version 1)
    思路发现,如果相邻元素的奇偶性相同,那么一定能通过在较低的位置竖着放若干个如果在\(i\)的位置竖着放一块砖头,使得这两列的高度相同。那么,我们想到直接考虑\(h_i\)的奇偶性,即将\(h_i\leftarrowh_i\bmod2\)。如果\(h_i=h_{i+1}\),我们显然可以同时使\(h_i\)和\(h......
  • [题解]CF1070C Cloud Computing
    思路考虑用线段树维护区间信息:价格在\([l,r]\)之间的CPU的数量。购买所有价格在\([l,r]\)之间CPU所需的钱。容易将区间修改转化为差分,从而实现单点修改。于是可以使用\(n\)个vector存储第\(i\)天所需进行的修改。查询第\(i\)天的答案时,如果不足\(k\)......
  • [题解]CF1746B Rebellion
    思路首先我们需要看到题目一个特殊的地方:这个序列中只存在\(0\)和\(1\)。那么,我们不难发现最终的答案一定是形如下面的序列:\(0,\dots,0,1,\dots,1\)。知道了这些,就很好想了。我们从后往前枚举,如果当前一位为\(0\)了,就从\(last\simi\)扫一遍,如果有\(1\)将最靠前的\(......
  • [题解]CF1742G Orray
    思路做这道题之前,首先要知道一个性质:\(a\operatorname{or}b\geqa\)。那么,我们就能得出一个结论:经过一定顺序的排列,最多经过\(\lceil\log_2^{a_{\max}}\rceil\)个数就能让前缀或的值达到最大值。我们不妨令有一个位置\(i\),\(b_1,b_2,\dots,b_{i-1}\)单调递增,而\(b_i......
  • [题解]CF1742E Scuza
    2022/11/23:修改了一下代码。题意有\(T\)组数据,每次给出一个\(n,q\),表示台阶的数量和询问的次数。然后再给出一个\(a_i\)为台阶高度的差分数组。每次询问给出一个\(k\),表示每次能走\(k\)个单位的高度。问:最高能到达的高度。思路考虑暴力,我们知道了高度的差分数组,那......
  • [题解]CF1741D Masha and a Beautiful Tree
    思路我们可以观察样例,不难发现:对于任意一段长度为\(2^k\)的区间中,如果最大值减最小值加\(1\)等于此区间的长度,那么一定有解。因为,我们的目标是使整个序列升序排列。因此,我们在一个区间内的最大值减最小值加\(1\)与区间长度是相等的。所以,我们可以用上述结论为判断无解的......
  • [题解]CF1741B Funny Permutation
    思路简单构造题,我们可以分为三种情况进行构造。\(n=3\)时,一定无解,输出-1。(你可以试试)\(n\bmod2=1\wedgen\neq3\)时,我们直接先输出\(n,n-1\),然后顺序输出即可。证明:令\(a\)为最后构造出的序列。那么,\(a_1=n,a_2=n-1,a_i=i-2(3\leqi\leq......