cf Educational Codeforces Round 45 C. Bracket Sequences Concatenation Problem

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/tengfei461807914/article/details/81745282

原题:
C. Bracket Sequences Concatenation Problem
time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
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 n bracket sequences s1,s2,…,sn. Calculate the number of pairs i,j(1≤i,j≤n) such that the bracket sequence si+sj is a regular bracket sequence. Operation + means concatenation i.e. “()(” + “)()” = “()()()”.

If si+sj and sj+si are regular bracket sequences and i≠j, then both pairs (i,j) and (j,i) must be counted in the answer. Also, if si+si is a regular bracket sequence, the pair (i,i) must be counted in the answer.

Input
The first line contains one integer n(1≤n≤3⋅10^5) the number of bracket sequences. The following n lines contain bracket sequences — non-empty strings consisting only of characters “(” and “)”. The sum of lengths of all bracket sequences does not exceed 3⋅10^5.

Output
In the single line print a single integer — the number of pairs i,j(1≤i,j≤n) such that the bracket sequence si+sj is a regular bracket sequence.

Examples
input
3
)
()
(
output
2
input
2
()
()
output
4
Note
In the first example, suitable pairs are
(3,1) and (2,2).
In the second example, any pair is suitable, namely
(1,1),(1,2),(2,1),(2,2)
.

中文:

给你n个括号序列,问你这n个括号序列,任意取两个括号序列(可以选两个一样的)组合到一起,总共有多少对合法的序列。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;


int n;
string s;
map<ll,ll> lb,rb;


bool judge(const string &x,ll &ls,ll &rs)
{
    stack<char> sc;
    for(int i=0;i<x.size();i++)
    {
        if(s[i]=='(')
        {
            sc.push(s[i]);
        }
        else
        {
            if(!sc.empty())
            {
                if(sc.top()=='(')
                    sc.pop();
                else
                    sc.push(s[i]);
            }
            else
                sc.push(s[i]);
        }
    }

    if(sc.empty())
        return true;

    char c=sc.top(),tmp;
    sc.pop();
    if(c=='(')
        ls++;
    else
        rs++;
    while(!sc.empty())
    {
        tmp=sc.top();
        sc.pop();
        if(tmp=='(')
            ls++;
        else
            rs++;
        if(c!=tmp)
            return false;
    }
    return true;

}

int main()
{
    ios::sync_with_stdio(false);

    while(cin>>n)
    {
        ll ls,rs,flag;
        lb.clear();
        rb.clear();
        for(int i=1;i<=n;i++)
        {
            cin>>s;
            ls=rs=0;
            if(judge(s,ls,rs))
            {
                if(ls==0&&rs==0)
                {
                    lb[0]++;
                    rb[0]++;
                }
                else
                {
                    if(ls!=0)
                        lb[ls]++;
                    else
                        rb[rs]++;
                }
            }
        }


        ll ans=0;
        for(auto x:lb)
        {
            if(rb.find(x.first)!=rb.end())
            {
                ans+=(x.second)*rb[x.first];
            }
        }
        cout<<ans<<endl;
    }


    return 0;
}

思路:

首先判断一个单独的括号序列是否是一个“可以组合”的括号序列,可以组合的意思就是只能在这个序列的左边或者右边添加适当的括号,使得该序列合法,例如:

“)(“ 就是一个不“可以组合”的括号序列

“()(”就是一个“可以组合”的括号序列

如果一个括号序列是“可以组合”的,那么最后左括号和右括号相互抵消后,仅剩余的左括号或者仅剩余的右括号数目,就是你需要在另外一侧添加的括号的数目,例如:

“()((()”是一个“可以组合”的括号序列,左括号的数目是4,右括号的数目是2,抵消后左括号数目为2。如果想要和这个括号序列相连接为一个合法的序列,需要找到一个抵消后的括号序列,其右括号数目为2,即可。

如何判断一个括号序列是否“可以组合”?

自己在纸上画一画可以找出规律,先利用栈来模拟括号匹配的方式,如果栈里面最后剩余的括号都是一种类型,那么就是一个“可以组合”的序列了。

猜你喜欢

转载自blog.csdn.net/tengfei461807914/article/details/81745282