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.
The first line contains one integer n(1≤n≤3⋅105)n(1≤n≤3⋅105) — the number of bracket sequences. The following nn lines contain bracket sequences — non-empty strings consisting only of characters "(" and ")". The sum of lengths of all bracket sequences does not exceed 3⋅1053⋅105.
In the single line print a single integer — 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.
3 ) () (
2
2 () ()
4
题意:给你n行括号序列,从中任选两个序列i,j,进行配对,如果i,j合二为一新序列括号完全匹配,即配对成功。同时i,j和j,i认为是两种方案,且i==j可取。问你最终配对方案总数。
思路:在解决本题之前,先介绍一个括号配对题的处理技巧,可以很容易的把问题转化为数字问题,非常实用。接下来描述的括号序列中都只含有‘(’‘)’。
任给一个括号序列s,我们应该立即得出:使得s完全匹配时,还需要左括号个数l,右括号个数r。
简单说明一下思路:令l=r=0,自左至右扫描序列,遇到‘(’则l++。当遇到‘)’时,有左括号肯定要利用的嘛,当l>0,l--,否则r++。
for(ll i=1;i<=len;i++)
{
if(s[i]=='(')l++;
else
{
if(l>0)l--;
else r++;
}
}
所得的l,r就是使序列s自身刚好匹配时,还需的左右括号数,这个结论对于一般的括号问题,都能有效的转化成统计数字的问题。
现在我们来看本题,选出两个进行接合,那么接合时,有一端必然是空着的,因此如果l,r都大于0,此时无论怎样都不可能配对的,这种序列直接丢掉就行了,然后预处理l>0,r==0的,map[l]++统计。之后l==0,r>0,可以发现当l==r时,匹配成功。这样我们就把括号序列问题转化为了数字匹配问题。
最后要注意,l=r=0的情况,此时把所有0单独处理,假设有x个0,匹配总数=C[x,2]*2+x=x^2。乘2即i,j j,i的情况。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<string>
#include<map>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#define ll long long
#define exp 1e-8
#define mst(a,k) memset(a,k,sizeof(a))
#define pi acos(-1.0)
using namespace std;
map<ll,ll>mp;
ll n,a[300030];
char s[300030];
int main()
{
while(~scanf("%lld",&n))
{
mp.clear();
for(ll i=1;i<=n;i++)
{
scanf("%s",s+1);
ll len=strlen(s+1),l=0,r=0;
for(ll i=1;i<=len;i++) //统计l,r
{
if(s[i]=='(')l++;
else
{
if(l>0)l--;
else r++;
}
}
if(l&&r) //转化成数字记录在数组中
{
i--;
n--;
continue;
}
else if(l) a[i]=l;
else a[i]=-r; //我把r保存成负数了,实现l+r==0,其实不用
}
ll zero=0;
for(ll i=1;i<=n;i++) //先统计l
{
if(a[i]>0)mp[a[i]]++;
if(a[i]==0)zero++;
}
ll ans=0;
for(ll i=1;i<=n;i++) //现在是r
{
if(a[i]<0)
{
a[i]*=-1;
if(mp[a[i]])
{
ans+=mp[a[i]];
}
}
}
ans+=zero*zero; //把所有0单独处理,公式就是组合数推导一下就行了
printf("%lld\n",ans);
}
return 0;
}