CF990C

写这题主要是补一下之前比赛出的锅吧

题意就是给一堆括号序列,
问用任意两个下标可以相同的序列可以拼出的合法序列个数(区分前后)

实际上比赛的时候就差一个特判(大概?)就 A 了

考虑什么样的序列对会对答案产生贡献,
显然是满足 S_i的未匹配左括号数 等于 S_j的未匹配右括号数 的对

发现有些序列是不可能产生贡献的,比如 ")(" ")(()" 

枚举几个串之后发现它无一例外是去掉已匹配字串后左边有右括号且右边有左括号的

这种情况只要在读入的时候拿个栈就能搞掉,然后就可以愉快的统计答案了

注意要开 long long


 代码:

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <cstdio>
using namespace std;

typedef long long ll;
const int MAXN = 300005;

int n, totlen, siz0, maxlen;
ll ans;
int lef[MAXN], rig[MAXN];
char str[MAXN], stk[MAXN];

inline int rd() {
	register int x = 0;
	register char c = getchar();
	while (!isdigit(c)) c = getchar();
	while (isdigit(c)) {
		x = x * 10 + (c ^ 48);
		c = getchar();
	}
	return x;
}
inline void getstr(int &pos, char *s) {
	register int top = 0, cnt = 0;
	register char c = getchar();
	while (c != '(' && c != ')') c = getchar();
	while (c == '(' || c == ')') {
		if (stk[top] == '(' && c == ')') --top;
		else stk[++top] = c;
		c = getchar();
	}
	if (stk[top] == '(' && stk[1] == ')') return;
	for (int i = 1; i <= top; ++i) {
		cnt += (stk[i] == '(' ? 1 : -1);
		s[++pos] = stk[i];
	}
	if (!cnt) ++siz0;
	else if (cnt > 0) ++lef[cnt];
	else ++rig[-cnt];
	maxlen = max(maxlen, abs(cnt));
	return;
}

int main() {
	scanf("%d", &n);
	register int tmp = 0;
	for (int i = 1; i <= n; ++i) 
		getstr(totlen, str);
	for (int i = 1; i <= maxlen; ++i) if (lef[i]) ans += (ll)lef[i] * rig[i];
	ans += (ll)siz0 * siz0;
	printf("%lld\n", ans);
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/xcysblog/p/9826863.html
今日推荐