JZOJ Day4 B组 T2【五校联考1day1】已经没有什么好害怕的了

题目大意:

小Y 最近开始学习算法姿势,但是因为小R 非常BB,给了她很多B6 题,所以她觉得自己已经没有什么前途了。于是小R 给了她一些稍微简单的题,让她觉得已经没有什么好害怕的了,其中一道是这样的:
给定一个长度为n 只包含左括号和右括号的序列,现在小R 想要知道经过每一个位置的合法子串有多少个。
空串是一个合法的串,如果A 和B 都是合法的串,那么(A) 和AB 都是合法的串。


解题思路:

把左括号视为 1 1 1,右括号视为 − 1 -1 1,处理处前缀和数组 w w w。子串 [ L , R ] [L, R] [L,R] 满足条件当且仅当
w L − 1 = w R w_L−1 = w_R wL1=wR 且对所有的 L ≤ i ≤ R 都有 w i ≥ w R w_i ≥ w_R wiwR
那么我们可以先把所有位置按照 w w w 权值从大到小排序(桶排),然后建一个
双向链表,开始所有节点都在链表中,从大到小(值相同先考虑位置较大的)考虑每一个点,
此时它的前驱一定是在它前面第一个权值小于等于它的点,这样就可以求出以每一个点为右端
点最短的满足条件的串是什么。得到了这个之后随便递推一下就可以得到 a n s ans ans 数组了。
时间复杂度 O ( n ) O(n) O(n)


A c c e p t e d   c o d e : Accepted\ code: Accepted code:

#include<stack>
#include<cstdio>
#include<cstring>
#define int long long
#define iint int
#define Int register int
#define Mem(x) memset(x, 0, sizeof(x))

using namespace std;

const int Mod = 1e9 + 7;
const int Maxn = 1e6 + 5;

iint T, N, len, p, q;
iint l[Maxn], r[Maxn], pre[Maxn], nxt[Maxn];
int ans[Maxn], sum;
char c[Maxn];

void write(int x) {
	if (x > 9) write(x/10); putchar(x%10+48); return;
}

void writeln(int x) {
	write(x); putchar(10);
}

signed main() {
	stack <int> s;
	scanf("%d", &T);
	while(T--) {
		while(s.size()) s.pop();
		sum=0; Mem(l); Mem(r);
		Mem(ans); Mem(pre); Mem(nxt);
		scanf("%s", c + 1);
		N = strlen(c + 1);
		for (Int i = 1; i <= N; ++i) {
			if (c[i] == '(') s.push(i); else
			if(s.size()) nxt[s.top()] = i + 1, pre[i+1] = s.top(), s.pop();
		}
		for (Int i = N + 1; i > 0; --i) r[pre[i]] += ++r[i];
		for (Int i = 1; i <= N; i++) l[nxt[i]] += --l[i];
		for (Int i = 1; i <= N; i++) {
			ans[i] = ans[~-i] + l[i] + r[i];
			sum += (ans[i] * i) % Mod;
		}
		writeln(sum);
	}
}
  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值