因为只有std,没有自我实现,所以是无码专区

主要是为了训练思维能力

solution才是dls正解,但是因为只有潦草几句,所以大部分会有我自己基于正解上面的算法实现过程,可能选择的算法跟std中dls的实现不太一样。

std可能也会带有博主自己的注释。


problem

给定一个由左右括号构成的字符串 sss,对于每一个位置 iii,定义 ansi:ans_i:ansi​: 有多少个子串满足这个子串是一个合法的括号序列,并且 iii 这个位置在子串中。

合法的括号序列定义:

  • 空串合法。
  • 如果 SSS 合法,那么 (S)(S)(S) 也是合法的。
  • 如果 S,TS,TS,T 合法,那么 STSTST 也是合法的。

由于答案很大,输出 ∑i=1∣S∣(i⋅ansimod109+7)\sum_{i=1}^{|S|}\Big(i·ans_i\mod{10^9+7}\Big)∑i=1∣S∣​(i⋅ansi​mod109+7),注意是先取模再相加,相加后并不需要取模。

∣S∣≤107,1s,512MB|S|\le 10^7,1s,512MB∣S∣≤107,1s,512MB。


my idea

套路的,将括号序列转化为 ±1±1±1 分数序列,左括号为 +1+1+1,右括号为 −1-1−1。并求前缀和

当一个串为合法括号序列,当且仅当每个位置的前缀和都不小于 000 ,且最后一个位置的前缀和恰好为 000。

保证了没有中途右括号个数多于左括号个数,以及最后左右括号个数匹配,显然这是充要条件。

考虑枚举合法括号序列的左端点。

可以肯定的是,被枚举的位置 iii 本身首先得是个 (

通过某种手段快速找到 iii 后面的第一个小于 000 的前缀和位置 jjj。因为从 jjj 开始后面就一定不合法了。

注意以下的前缀和若无特殊说明,都是指以 iii 开始的前缀和,所以应该满足 sumj−sumi−1<0sum_j-sum_{i-1}<0sumj​−sumi−1​<0。

显然,jjj 位置一定是个 ),且 [i,j)[i,j)[i,j) 一定是一个合法括号序列。当然这个性质没有什么用。有用的只是 jjj 的位置。

特殊地,如果一直到最后 ∣S∣|S|∣S∣ 都没找到,就返回 ∣S∣+1|S|+1∣S∣+1 即可。

考虑二分,但很容易发现这并不具有连续性,错误。

考虑线段树,相当于在 iii 时去考虑小于 sumi−1sum_{i-1}sumi−1​ 的 sumjsum_jsumj​。

具体而言:

从后往前做,到 iii 时线段树上储存的是 [i,n][i,n][i,n] 的前缀和(此前缀和是指从 111 开始的)。

线段树是权值线段树,每个叶子权值储存的是距离 iii 最近的下标 jjj。

所以查询就是在线段树上 [1,sumi−1)[1,sum_{i-1})[1,sumi−1​) 区间查询最小的节点权值。

即以权值为线段树上的下标,以下标为线段树上的权值。

维护区间最小值。

修改:每次 iii 前移 −1-1−1,就把 iii 的前缀和对应的线段树上叶子节点权值更改为 iii。

确定了整个大区间,考虑其中的的合法序列,即 s[i,k],i<k<js[i,k],i<k<js[i,k],i<k<j 的合法括号序列。

显然只需要满足 kkk 的前缀和为 000 即可。

现在的问题是怎么迅速找到这些 kkk,并快速计算贡献。

先考虑快速计算贡献,显然 [i,k][i,k][i,k] 一段合法括号序列会让 i≤x≤ki\le x\le ki≤x≤k 的 ansxans_xansx​ 都 +1+1+1。

所以这里采取差分手段,对 ansk+1,ansi−1−1ans_k+1,ans_{i-1}-1ansk​+1,ansi−1​−1,最后的时候来一次后缀和,每个 ansxans_xansx​ 都是正确的了。

最后就只剩下迅速找到这些 kkk 的问题了。

一开始就将所有的前缀和 sumisum_isumi​(这里的前缀和是指以 111 开始的)桶排序。

即以 sumisum_isumi​ 为桶下标分装所有的前缀和,用 vector 存储,桶内放的是前缀和下标。

然后从前往后考虑左端点 iii,找到 sumisum_isumi​ 的那个桶,以 jjj 为分解线二分出最大的小于 jjj 的位置 ppp,然后桶内前 ppp 个的点对应的 ansansans 都可以差分 +1+1+1。

显然也不能枚举 1∼p1\sim p1∼p 一个一个加,所以在桶里面也进行前缀和差分,在 111 位置 +1+1+1,在 p+1p+1p+1 位置 −1-1−1。

每次在二分之前,都得先在 sumisum_isumi​ 的桶内把第一个元素丢出去,在丢之前又得把差分数组及时传递。

所以在 iii 时,所有桶内都只有 i+1∼∣S∣i+1\sim |S|i+1∼∣S∣ 的前缀和(这里的前缀和是指 111 开始的),并且桶内的差分是更新过的,

意思就是如果要扔去某个桶的对头 xxx(桶内存的是下标),对头下一个是 yyy,那么差分数组更新一下 ansy+=ansxans_y+=ans_xansy​+=ansx​。

因为第二个部分的桶是从前往后做,第一个部分是从后往前做,顺序不同所以要分开做。

桶内前缀差分,差分完后,桶外后缀差分。

时间复杂度:O(nlog⁡n)O(n\log n)O(nlogn)。

只能通过 70%70\%70% 的数据点 ∣S∣≤106|S|\le 10^6∣S∣≤106。


solution

凸(艹皿艹 ) O(nlog⁡n)O(n\log n)O(nlogn) 尼玛思维代码量比 O(n)O(n)O(n) 还难。

首先处理一下哪些括号是匹配的,用栈来做。

w(X()X(Z()Z)X(Y()Y()Y)X()X)W ,把括号之间的间隔标号,对于一堆匹配的括号,即合法括号序列,要求两端的标号相同。

第一次见这种处理,是小生孤陋寡闻了Orzqwqqwq

问题转化为,有若干个标号,要统计位置 iii 两端有多少对标号是相同的。

dls题解就给个思路,还是得自己仔细想具体代码算法实现。qwq

对于每个匹配括号 ()()(),对于左括号 iii ,记录一个 upiup_iupi​,upiup_iupi​ 是最小的能包含这对匹配括号的另一对匹配括号的左括号位置。

(..(..)...),第一个左括号就是 upiup_iupi​,这期间要保证不存在 upi<x<i,match(i)<y<match(upi),x,yup_i<x<i,match(i)<y<match(up_i),x,yupi​<x<i,match(i)<y<match(upi​),x,y 能匹配。

类似前缀和差分,ansupi→ansians_{up_i}\rightarrow ans_iansupi​​→ansi​。

用 ai,bi:a_i,b_i:ai​,bi​: 记录左右的连续可完美匹配的括号。

(..()..)(..)(..) 第三个左括号和第三个右括号假设是现在 iii 对应的匹配,那么可以选择第一个左括号到第三个右括号,第一个左括号到第四个右括号。

这就用 ai∗bmatch(i)a_i*b_{match(i)}ai​∗bmatch(i)​ 来统计,具体实现可以看 std。

时间复杂度: O(n)O(n)O(n)。


std

#include <bits/stdc++.h>
#define LL long long
#define LD long double
#define ull unsigned long long
#define fi first
#define se second
#define mk make_pair
#define PLL pair<LL, LL>
#define PLI pair<LL, int>
#define PII pair<int, int>
#define SZ(x) ((int)x.size())
#define ALL(x) (x).begin(), (x).end()
#define fio ios::sync_with_stdio(false); cin.tie(0);using namespace std;const int N = 1e7 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-8;
const double PI = acos(-1);template<class T, class S> inline void add(T &a, S b) {a += b;if (a >= mod)a -= mod;
}template<class T, class S> inline void sub(T &a, S b) {a -= b;if (a < 0)a += mod;
}template<class T, class S> inline bool chkmax(T &a, S b) {return a < b ? a = b, true : false;
}template<class T, class S> inline bool chkmin(T &a, S b) {return a > b ? a = b, true : false;
}mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());int n;
int stk[N], top;
int match[N], a[N], b[N], up[N];
int ans[N];
char s[N];int main() {freopen("bracket.in", "r", stdin);freopen("bracket.out", "w", stdout);scanf("%s", s + 1);n = strlen(s + 1);top = 0;for (int i = 1; i <= n; i++) {if (s[i] == '(') { //左右括号匹配 up[i]:i位置前最靠近i的还未匹配的左括号/*因为up[i]是还未匹配的,所以up[i]匹配的右括号一定是包含i的(如果能匹配的话)即长相为 (..(..)...) */up[i] = stk[top];stk[++top] = i;} else if (top) {match[i] = stk[top];match[stk[top]] = i;top--;}}for (int i = 1; i <= n; i++) {if (!match[i] || s[i] == '(')continue;b[i] = b[match[i] - 1] + 1; //b[i]标号右括号 b[i]:i位置右括号的标记应为匹配的左括号前一个位置的标号+1}for (int i = n; i >= 1; i--) {if (!match[i] || s[i] == ')')continue;a[i] = a[match[i] + 1] + 1;//a[i]标号左括号 a[i]:i位置左括号的标记应为匹配的右括号后一个位置的标号+1}
//+1表示只选i-j这对匹配括号for (int i = 1; i <= n; i++) {if (!match[i] || s[i] == ')')continue;ans[i] = 1LL * a[i] * b[match[i]] % mod;if (up[i])add(ans[i], ans[up[i]]);ans[match[i]] = ans[i];}LL ret = 0;for (int i = 1; i <= n; i++) {ret += 1LL * ans[i] * i % mod;}printf("%lld\n", ret);return 0;
}

【无码专区7】括号序列(思维)相关推荐

  1. 【无码专区9】序列统计(带权并查集 + 前缀和建边 + dp)

    因为只有std,没有自我实现,所以是无码专区 主要是为了训练思维能力 solution才是dls正解,但是因为只有潦草几句,所以大部分会有我自己基于正解上面的算法实现过程,可能选择的算法跟std中dl ...

  2. 【无码专区2】序列划分(数学)

    有std,但是没有自我实现,所以是无码专区 description 完全由数字组成的字符串 sss,划分成若干段,每一段看成一个十进制的数(允许前导零)求有多少种划分方法使得相邻两个数至少一个是 DD ...

  3. 【无码专区13】最小公倍数(线段树)

    因为只有std,没有自我实现,所以是无码专区 主要是为了训练思维能力 my idea顾名思义,记录了我的整个思维过程,以及自己部分实现细节口胡,还有期望分数 solution才是dls正解,但是因为只 ...

  4. 【无码专区10】第K大查询(双向链表 /主席树+st表)

    已自我实现,但还是归入无码专区序列.哈哈哈哈哈 对于my idea部分,我的每一个想法都实现了,可供参考. problem 给定一个 1∼n1\sim n1∼n 的排列和 kkk,求所有 r−l+1≥ ...

  5. 【无码专区12】子集和(背包dp)

    此题已自我实现,但仍归于无码专区 本题在考场上就过了,所以难度并不高,发现性质即可. problem 有 nnn 个正整数 a1,a2,...,ana_1,a_2,...,a_na1​,a2​,... ...

  6. 【无码专区11】异或2(结论 / 推式子 + 哈希hash + 大整数高精度 加减乘除重载考察)

    本题已自我实现.但仍归于无码专区 problem 求 ∑i=1n−1i⨁(n−i)\sum_{i=1}^{n-1}i\bigoplus (n-i)∑i=1n−1​i⨁(n−i). 20%,n≤1e6; ...

  7. 【无码专区8】三角形二维数点——计数有多少个给定点落在三角形区域内

    因为只有std,没有自我实现,所以是无码专区 主要是为了训练思维能力 solution才是dls正解,但是因为只有潦草几句,所以大部分会有我自己基于正解上面的算法实现过程,可能选择的算法跟std中dl ...

  8. 【无码专区6】球与盒子(数学线性筛)

    因为只有std,没有自我实现,所以是无码专区 主要是为了训练思维能力 solution才是dls正解,但是因为只有潦草几句,所以大部分会有我自己基于正解上面的算法实现过程,可能选择的算法跟std中dl ...

  9. 【无码专区5】01串(大讨论+构造)

    因为只有std,没有自我实现,所以是无码专区 主要是为了训练思维能力 solution才是dls正解,但是因为只有潦草几句,所以大部分会有我自己基于正解上面的算法实现过程,可能选择的算法跟std中dl ...

最新文章

  1. eye caring sticker
  2. Springboot对web应用的统一异常处理
  3. 实现网站验证码切换功能
  4. UVa 208 Firetruck【回溯】
  5. PSIM软件学习---01初识别PSIM软件
  6. 【报告分享】2019云安全威胁报告.pdf(附下载链接)
  7. c java通讯_java与c通讯
  8. 编写一个Java应用程序,从键盘读取用户输入两个字符串,并重载3个函数分别实现这两个字符串的拼接、整数相加和浮点数相加。要进行异常处理,对输入的不符合要求的字符串提示给用户,不能使程序崩溃。
  9. 微信公众号网页链接失效解决方案
  10. HOUR 11 Developing Advanced Pointers
  11. 经典上海弄堂线路攻略
  12. 计算机专业实训图片,实训一图片的简单处理_计算机软件及应用_IT计算机_专业资料...
  13. 阿里云服务器1核1G内存1M带宽能放几个网站及多少流量
  14. 计算机画图学生作品小学,电脑绘画作品_需要一件小学生电脑绘画作品
  15. 倍福--通知方式实现ADS通信
  16. cocos creator开发微信小游戏(五)贪吃蛇大作战
  17. 飞凌imx6dl lvds闪屏问题记录
  18. Python编程 | 系统编程 | 脚本运行上下文 | 标准流
  19. STM8L051之ADC+DMA两通道数据采样错位问题
  20. 攒机笔记六(机械硬盘)

热门文章

  1. linux浏览器不能播放音频文件夹,在html中插入音频文件在浏览器中播放音频文件的兼容性问题...
  2. android studio 创建.9文件,自己使用Android studio创建.9(点9)图片
  3. 重力模型matlab代码,STK基础教程.doc
  4. php pdo 查询语句,PDO:预处理语句(参数化查询)
  5. python字符串设置字体_python怎么更改字符串后几位
  6. 问题 B: 数塔问题
  7. C++ setprecision()用法
  8. 2.5w字长文爆肝 C++动态内存与智能指针一篇搞懂!太顶了!!!
  9. hdu2648 Shopping-map容器
  10. [蓝桥杯][2014年第五届真题]分糖果-模拟