【CodeForces 990C】 Bracket Sequences Concatenation Problem

题目链接

luogu &  CodeForces

题目描述

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

时间: 2024-10-13 20:08:38

【CodeForces 990C】 Bracket Sequences Concatenation Problem的相关文章

Bracket Sequences Concatenation Problem CodeForces - 990C(括号匹配水题)

明确一下  一个字符串有x左括号不匹配  和 另一个字符串有x个右括号不匹配  这俩是一定能够匹配的 脑子有点迷 emm... 所以统计就好了  统计x个左括号的有几个,x个右括号的有几个 然后 乘一下 如果一个串 同时存在左右括号都不匹配的情况 则忽略 因为这个串需要另外两个括号去匹配 不要忘了处理左右括号已经匹配的情况 #include <bits/stdc++.h> using namespace std; const int maxn = 1e6+5, INF = 0x7fffffff

【Codeforces 264B】Good Sequences

[链接] 我是链接,点我呀:) [题意] 让你在一个递增数组中选择一个最长子序列使得gcd(a[i],a[i+1])>1 [题解] 设f[i]表示以一个"含有素因子i的数字"作为序列的结尾的最长序列的长度 显然更新的时候 假设枚举到了a[i] 先求出它所有的素因子p[] 因为要和前面一个数字不互质 那么只能找结尾数字有这些素因子p[]的数字 因此我们求出f[p[1~cnt]]中的最大值Ma,他们最大值对应的序列再加上一个a[i]的话 长度就变成Ma+1了 然后f[p[1~cnt]

【codeforces 718E】E. Matvey&#39;s Birthday

题目大意&链接: http://codeforces.com/problemset/problem/718/E 给一个长为n(n<=100 000)的只包含‘a’~‘h’8个字符的字符串s.两个位置i,j(i!=j)存在一条边,当且仅当|i-j|==1或s[i]==s[j].求这个无向图的直径,以及直径数量. 题解:  命题1:任意位置之间距离不会大于15. 证明:对于任意两个位置i,j之间,其所经过每种字符不会超过2个(因为相同字符会连边),所以i,j经过节点至多为16,也就意味着边数至多

【codeforces 415D】Mashmokh and ACM(普通dp)

[codeforces 415D]Mashmokh and ACM 题意:美丽数列定义:对于数列中的每一个i都满足:arr[i+1]%arr[i]==0 输入n,k(1<=n,k<=2000),问满足[数列长度是k && 数列中每一个元素arr[i]在1~n之间 && 数列中元素可以重复]的数列有多少个?结果对10^9+7取余 解题思路:dp[i][j]表示长度是j,最后一位是i的种数 if(kk%i==0) dp[kk][j+1]+=dp[i][j] 1 #i

【Codeforces 368A】Brain&#39;s Photos 水题

黑白灰都是#Black&White #include <cstdio> int n,m; int main() { scanf("%d%d",&n,&m); int ok=0; for(int i=0;i<n;i++) for(int j=0;j<m;j++) { char s[5]; scanf("%s",s); if(s[0]!='W'&&s[0]!='B'&&s[0]!='G')

【Codeforces 1114C】Trailing Loves (or L&#39;oeufs?)

[链接] 我是链接,点我呀:) [题意] 问你n!的b进制下末尾的0的个数 [题解] 证明:https://blog.csdn.net/qq_40679299/article/details/81167283 这题的话m比较大, 做个质因数分解就ok>_< 算n!有多少个x因子的话 以5为例子 (n=25) 25 20 15 10 5 把他们都除5 5 4 3 2 1 然后再除5 1 所以总共有6个 转换成代码就是 while(n>0){ ans+=n/5; n = n/5; } [代码

【Codeforces 332C】Students&#39; Revenge

Codeforces 332 C 我爱对拍,对拍使我快乐... 题意:有\(n\)个议题,学生们会让议会同意\(p\)个,其中主席会执行\(k\)个, 每一个议题执行后主席会掉\(a_i\)的头发,不执行后议会会增加\(b_i\)的不开心值, 然后主席想让议会的不开心值最小,如果有多重方案就选自己头发掉的最少的: 而学生们想让主席的头发掉的最多,如果有多种方案让议会的不开心值最大. 问让议会同意哪\(p\)个会达到最好的效果. 思路1: 这是我的不对的思路. (虽然没提交 我们首先将所有的数按照

【尺取法】Jessica&#39;s Reading Problem

Step1 Problem 原题 一个人复习一本书,这本书的每一页都有一个知识点ai,每一页的知识点可能会与其他页的知识点相同,问你如何读最少页,将所以知识点读完. Step2 Ideas: 尺取法通常是指对数组保存下一对下标(起点.终点),燃豆很具实际情况交替推进两个端点直到得出答案的方法.确定下知识点的个数,便用尺取法推进得到答案. Step3 Code: #include<iostream> #include<stdio.h> #include<iomanip>

【Codeforces 429D】 Tricky Function

[题目链接] http://codeforces.com/problemset/problem/429/D [算法] 令Si = A1 + A2 + ... + Ai(A的前缀和) 则g(i,j) = Sj - Si f(i,j) = (i-j)^2 + (Si - Sj)^2 观察这个式子,我们发现可以用类似于平面最近点对的算法来求解该问题 [代码] #include<bits/stdc++.h> using namespace std; #define MAXN 100010 const