首页 > 其他分享 >P9356 「SiR-1」Bracket 题解

P9356 「SiR-1」Bracket 题解

时间:2023-05-28 17:55:14浏览次数:58  
标签:pre SiR 题解 sum st ge Bracket 序列 mathcal

P9356 「SiR-1」Bracket 题解

首先我们来先考虑一下如何计算一个给定的 \(f(s[1,n])\)。

一般括号序列的题目都是比较套路的将 \(\texttt{(}\) 赋值为 \(1\),将 \(\texttt{)}\) 赋值为 \(-1\),然后求一下前缀和记为 \(sum_i\),那么一个括号序列是合法的当且仅当 \(\forall i\in[1,n],sum_i\ge 0\)。

然后观察本题的操作可以发现由于操作二是任意地进行循环位移,所以我们最多进行一次操作二(因为任意两次操作二都可以合并成一次),那么我们接下来只用考虑需要进行几次操作一、什么时候进行操作二。

引理一:

如果 \(sum_n=0\) 那么我们一定可以通过最多一次操作二使得该序列合法。

证明:

我们记 \(sum_p=\min_{i=1}^{n}sum_i\),所以 \(\forall i\in[1,n]sum_i-sum_p\ge0\)。

如果 \(sum_p\ge 0\),那么显然引理一得证,下面考虑 \(sum_p<0\) 的情况。

由于 \(sum_n=0\),因此 \(\sum_{i=p+1}^{n}a_i=sum_n-sum_p=-sum_p\),那么如果我们将 \(s[p+1,n]\) 移动到最前面,则新的 \(\{sum_i'\}\) 就满足:

\[\begin{cases} sum'_i=sum_{i+p}-sum_p\ge0,&i\in[1,n-p]\\ sum'_i=sum_{i-p}+sum_{n-p}\ge0,&i\in[n-p+1,n] \end{cases} \]

故此时的括号序列合法。综上所述引理一得证。

所以说对于一个括号序列 \(s[l,r]\),如果我们最后不管是否需要都进行一次操作二,那么他变成合法序列的操作数就是 \(|sum_r-sum_{l-1}|+1\),故本题要求的答案为:

\[ans=\sum_{l=1}^{n}\sum_{r=l}^{n}f(s[l,r])=\dfrac{n(n+1)}{2}+\sum_{l=1}^{n}\sum_{r=l}^{n}|sum_r-sum_{l-1}| \]

求这个式子的话可以分成两类,\(sum_r\ge sum_{l-1}\) 和 \(sum_r<sum_{l-1}\),然后分别计算答案,这个可以用值域树状数组在 \(\mathcal O(n\log n)\) 的时间复杂度内完成,具体的,记 \(val_i,num_i\) 表示当前的 \(\sum_{l=1}^{r}sum_{l-1}[sum_{l-1}\le i]\) 和 \(sum_{l=1}^{r}[sum_{l-1}\le i]\),然后对于以 \(r\) 结尾的区间的贡献就是:\((num_{sum_r}\times sum_r-val_{sum_r})+(val_{inf}-(num_{inf}-num_{sum_r})\times sum_r)\)。

但是这一部分其实是可以在 \(\mathcal O(n)\) 的时间复杂度内完成的,因为我们关心的只是所有二元组 \((x,y)\) 的 \(|sum_y-sum_x|\) 的和(\(x\in[0,n],y\in[0,n]\)),并不关心 \(x,y\) 的大小关系,因此我们可以直接按照 \(sum_i\) 的值从小到大排序,答案就是:

\[\sum_{i=0}^{n}(sum_i\times i- \sum_{j=0}^{i-1}sum_{j}) \]

这是可以 \(\mathcal O(n)\) 求解的,而由于 \(sum_i\in[-n,n]\),所以说可以桶排,排序复杂度也是 \(\mathcal O(n)\),故总复杂度 \(\mathcal O(n)\)。

这一部分说完了,接下来只剩一个问题,求出不需要进行操作二的区间的个数 \(tot\)。那么最终的答案 \(res=ans-tot\)。

引理二:

一个括号序列 \(s[1,n]\) 进行完操作一后不需要进行操作二的充要条件是 \(sum_n=\min_{i=1}^{n}sum_i\) 或 \(\min_{i=1}^{n}sum_i\ge0\)。

证明:

这里我们记 \(mn=\min_{i=1}^{n}sum_i\),进行完操作一之后序列长度为 \(m\)。首先容易想到一个贪心的策略:我们在进行操作一的时候,如果要加入 \(\texttt{(}\) 一定是将它放到序列最前面,否则将它放到序列最后面,这样我们才能让进行操作一之后的前缀和序列 \(\{sum'_i\}\) 的值尽可能的大,然后我们分两类来考虑。

第一种,当 \(mn\ge 0\) 时,这时我们只在序列后面加入 \(\texttt{)}\),并且最终 \(sum'_m=0\),而显然 \(sum'_i\ge sum'_m,i\in[n+1,m]\),因此当 \(mn\ge0\) 时该括号序列不需要进行操作二。

第二种,当 \(mn<0\) 时,这时候如果 \(sum_n\ge 0\) 显然需要进行操作二,而当 \(sum_n<0\) 时会在序列前方加入 \(-sum_n\) 个 \(\texttt{(}\),那么就有 \(sum'_{i-sum_n}=sum_i-sum_n,i\in[1,n]\),而要保证 \(sum'_i\ge 0,i\in[1,m]\),故 \(sum_i-sum_n\ge 0,i\in[1,n]\),也即 \(mn-sum_n\ge 0\),因此只有当 \(sum_n=mn\) 时才不需要进行最后一次操作二。

综上所述,不需要进行操作二需要满足 \(sum_n=mn\or mn\ge 0\)。

接下来我们考虑如何统计原题目中各个子序列中满足上述条件的序列的数量。由于上述条件涉及到区间最小值,所以说很容易想到用单调栈去维护,然后枚举右端点,将右端点不断向右移动。现在我们记 \(st\) 为一个维护 \(sum_i,i\in[0,r]\) 的单调栈,里面的值单调递增,\(st\) 里存的是下标,即 \(st_{top}=r\)。

那么对于 \(mn=sum_n\) 这个条件,显然需要满足 \(l\in(st_{top-1},r]\),区间个数为 \(r-st_{top-1}\),复杂度 \(\mathcal O(n)\)。

而对于 \(mn\ge 0\),我们需要分段考虑,总的个数为:

\[\sum_{i=1}^{top-1}\sum_{j=st_{i-1}}^{st_i}[sum_{st_i}\ge sum_j] \]

这个式子可以用值域树状数组维护,复杂度 \(\mathcal O(n\log n)\),但可以继续优化。

如果我们记 \(pre_i\) 为它插入单调栈时他前面的那一个数的下标,则如果 \(i\) 此时在单调栈中那么他对 \(r\) 这个右端点的答案的贡献就是 \(\sum_{j=pre_i+1}^{i}[sum_i\ge sum_j]\)。而又由于每一个值 \(i\in[1,n]\),他的 \(pre_i\) 的值只有一个,所以它的贡献也是唯一确定的,因此只要我们能 \(\mathcal O(n)\) 求出所有 \(\sum_{j=pre_i+1}^{i}[sum_i\ge sum_j]\) 就行了,而这个式子其实和我们维护单调栈的过程十分类似——维护单调栈是将 \([pre_i+1,i-1]\) 之间所有 \(sum_j\ge sum_i\) 的 \(j\) 给 \(pop\) 掉了,而 \(\sum_{j=pre_i+1}^{i}[sum_i\ge sum_j]=i-pre_i-\sum_{j=pre_i+1}^{i-1}[sum_i \ge sum_j]+\sum_{j=pre_i+1}^{i-1}[sum_i=sum_j]\),这样就可以轻松 \(\mathcal O(n)\) 去维护了,具体的:

记 \(val_i\) 为 \(\sum_{j=pre_i+1}^{i-1}[sum_i\ge sum_j]\),\(ex_i=\sum_{j=pre_i}^{i-1}[sum_sum_j]\),\(S\) 为插入 \(i\) 时所有弹出栈的下标的集合,则:

\[val_i=\sum_{j\in S}val_j+1,ex_i=\sum_{j\in S}(ex_j+1)[sum_j=sum_i] \]

那么答案就是 \(\sum_{i=1}^{top-1}st_i-st_{i-1}-val_i+ex_i\),再稍微维护一下前缀和即可,如果不清楚的话可以看一下代码中的 tot[i]。这样我们就做到了 \(\mathcal O(n)\) 的时间复杂度。

好了到这里这道题就差不多结束了,这里有 \(\mathcal O(n\log n)\) 的 代码 和 \(\mathcal O(n)\) 的 代码

标签:pre,SiR,题解,sum,st,ge,Bracket,序列,mathcal
From: https://www.cnblogs.com/zyc070419-blog/p/17438568.html

相关文章

  • comp2123 问题解答
    comp2123Assignment5s12023Problem1.Wewanttodesignadivideandconqueralgorithmforcomputingtheunionofacollectionofrectangles.Theinputrectanglesarealignedwiththeaxesandtheyareallstabbedbythey-axis.Eachrectangleisrepresen......
  • LeetCode-Java题解 977. Squares of a Sorted Array
    题目地址:977.SquaresofaSortedArray解题思路:    又是一道双指针的题目,看见秒想到双指针(平方直接调用sort方法也行,但是这么写这题就没意思了)。但是,我一直在想,不增加空间消耗的情况下,如何进行排列,想了半天把自己绕进去了。开辟一个新数组,倒序放置就非常简单了。一定要利......
  • phpcms常见问题解答
    phpcms常见问题解答1.为什么phpcms首页幻灯片怎么显示不出来?答:需要设置文章的标题图片如果设置标题图片,则可以在首页以及栏目页以图片方式链接到文章。2.自定义phpcms的标签只能是全HTML?答:在自定义标签内容中可以插入html代码,也可以插入多个函数标签或者变量标签。插入函......
  • Gym102978C Count Min Ratio 题解
    赛时无人场切。震撼,震撼。学到许多。全程贺zak。首先我们套路推下式子。枚举左边的红蓝球个数,答案即为\[\begin{aligned}&\sum_{b=0}^B\sum_{r=0}^R\binom{b+r}b\binom{B-b+R-r}{B-b}\min(\fracrb,\frac{R-r}{B-b})\\=&\sum_{x=1}^{\fracRB}\sum_{b=0}^B\sum_{r=0}^R\binom......
  • Traceback (most recent call last):错误问题解决
    原因是没有配置pymysql配置mysql连接https://blog.csdn.net/zzzcl112/article/details/80503690#:~:text=%5Broot%40VM_0_8_centos%20local%5D%20%23%20tar%20-zxvf%20PyMySQL-0.8.1.tar.gz%20%E8%BF%9B%E5%85%A5%2Fusr%2Flocal%2FPyMySQL-0.8.1%E7%9B%AE%E5%BD%95%2C%E6%89%A7%E8%......
  • 时代的眼泪:CF1562A The Miracle and the Sleeper 题解 2021-09-23 23:00:33
    CF1562ATheMiracleandtheSleeper题解笑死,晚上熬夜打CF比赛只过了A题还加了CF值!?由于本人太弱,这道橙题都干了1h题目描述有\(T\)组数据,给出一个区间\([l,r]\),在这个区间中选择2个数a,b,使它们a%b的值最大.注意:\(l\ler\le10^9\),\(T\le10^3\)解题步骤暴力......
  • #296. 最强大脑 题解
    2021-09-2222:16:56星期三#296.最强大脑题解这是一道非常简单的bfs水题。。。。但是为什么没有人做呢?难道是因为网上搜不到?理解题意:输入为2个n*m大小矩阵。第一个矩阵表示每个点的分数值,第二个矩阵则表示这个点是否是特殊点(1&0)这里规定了一种移动方式,你可......
  • #295. 「BJWC2010」矩阵距离 题解 2021-09-23 21:42:32
    #295.「BJWC2010」矩阵距离又是一道需要真正思考了才可以做出来的水题。题目描述给出一个N*M的01矩阵,输出每个0到离这个点最近的1的距离。思考历程暴力由于$N\le10^3$如果在赛场上出现这个题,我们优先考虑暴力。暴力也是很简单,从每个为0的点出发bfs找到与最近的......
  • 第三届里奇杯编程大赛(初赛)题解(正在更新文字解释)
    A.签到签到题,直接输出即可。#include<bits/stdc++.h>usingnamespacestd;intmain(){ cout<<"HelloLiqicontest"; return0;}B.挂科读取到每个人的成绩后,判断符合挂科条件(分数$<p$)就\(res\)增加一位同学。#include<iostream>#include<algorithm>......
  • c++模板的引用类型参数折叠问题解释
    template<typenameT>voidf1(T&);实参可以是左值、const类型的左值,不能是右值。f1(i);  //正确,i是int型,T是intf1(c); //正确,i是constint型,T是constintf1(5); //错误 template<typenameT>voidf1(constT&);实参可以是左值、const类型的左值、......