题目链接
题目描述
A bracket sequence is a string containing only characters "(" and ")".
A regular bracket sequence is a bracket sequence that can be transformed into a correct arithmetic expression by inserting characters "1" and "+" between the original characters of the sequence. For example, bracket sequences "()()", "(())" are regular (the resulting expressions are: "(1)+(1)", "((1+1)+1)"), and ")(" and "(" are not.
You are given nn bracket sequences s1,s2,…,sns1,s2,…,sn. Calculate the number of pairs i,j(1≤i,j≤n)i,j(1≤i,j≤n) such that the bracket sequence si+sjsi+sj is a regular bracket sequence. Operation ++ means concatenation i.e. "()(" + ")()" = "()()()".
If si+sjsi+sj and sj+sisj+si are regular bracket sequences and i≠ji≠j, then both pairs (i,j)(i,j) and (j,i)(j,i) must be counted in the answer. Also, if si+sisi+si is a regular bracket sequence, the pair (i,i)(i,i) must be counted in the answer.
题目翻译(摘自luogu)
给出n个字符串,保证只包含‘(‘和‘)‘,求从中取2个字符串链接后形成正确的括号序列的方案数(每个串都可以重复使用)(像‘()()‘和‘(())‘这样的都是合法的,像‘)(‘和‘(‘这样的是不合法的)
输入:
第一行一个整数n
第二行到第n+1行每行一个字符串
输出:
方案数
感谢@zhaotiensn 提供翻译
解题思路
当然,首先能想到的就是n^2枚举,然后再O(len)进行判断,显然T到飞起??
然后我们想一想,先去掉O(len)的检验,这个套在n^2里实在是太过分了qwq
对于每一个串,里面有一些括号是可以直接匹配上的,那么我们先把他们处理出来,这样我们就不需要检验那么长了。 然后我们再想想,我们从一个串的左向右扫一遍,遇到‘)’就找上一个没有匹配的‘(’,然后把他们进行匹配,那么最后可能还剩下一些‘(’或‘)’没有办法进行匹配,我们用 l 表示没有匹配的‘(’的个数,r 表示为匹配的‘)’的个数。
那么,如果 l 和 r 都不等于零,那么这一个串显然是废的,因为你顶多在左边或者右边加一个串,匹配掉一个方向的括号,不可能消掉两边的括号。
相反的,如果 l 和 r 都等于零,那么拥有这些性质的串相互乱放都是可以的 ,比如串A和串B满足这个性质,则A+B和B+A都是合法的。 如果有zer个这样的串,那就有zer^2种组合方法。
如果一个串的 l 等于零,r不等于零,那么它和另一个r=0 且l等于它的r串就可以组合成一个完整的串。
这样记录一下l和r,整个扫一遍就OK了。
代码
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 int n; 7 char s[300050]; 8 int totl[300050],totr[300050]; 9 int zer; 10 int main(){ 11 cin>>n; 12 for(register int i=1;i<=n;i++){ 13 scanf("%s",s); 14 int len=strlen(s),l=0,r=0; 15 for(register int j=0;j<len;j++){ 16 if(s[j]==‘)‘&&!l)r++; 17 else if(s[j]==‘)‘)l--; 18 else if(s[j]==‘(‘)l++; 19 } 20 if(!l&&!r)zer++; 21 else if(!l)totr[r]++; 22 else if(!r)totl[l]++; 23 } 24 long long ans=0; 25 for(register int j=1;j<=300000;j++){ 26 ans+=(long long)totr[j]*totl[j]; 27 } 28 ans+=(long long)zer*zer; 29 cout<<ans<<endl; 30 }
原文地址:https://www.cnblogs.com/Fang-Hao/p/9248792.html