原题地址:http://codeforces.com/contest/990/problem/C
题意:给出n个字符串,字符串仅有’(‘和’)’,询问有多少对字符串可以组成完美匹配的括号。
思路: 先考虑当前已经是匹配的括号的时候,那么如果要再加一个字符串形成匹配括号的话,那么只能和同样是已经匹配的配对。所以假设有x个完美匹配的字符串,那么就应该会有 中方法。
那么如果当前是不匹配的话,就也是只能找不匹配的。然而不同的是,如果你当前缺少a个右括号,那么相应要匹配的应该是要多a个右括号。然后缺少的方案数*多的方案数,最后相加即可。
注意处理一个字符串无论如何都不能形成完美匹配的情况。(比如说 “)(“)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int n;
const int maxn = 3e5 + 5;
ll a[maxn], b[maxn]; //a是左括号,b是右括号,c是已经相等的
char str[maxn];
void check(char *s) {
int len = strlen(s + 1);
int flag = 0; //0为左
int left = 0;
int right = 0;
for(int i = 1; i <= len; i++) {
if(s[i] == '(') left++;
else if(s[i] == ')') right++;
if(right > left) flag = 1;
}
if(flag){//对于只能是在右边的情况再倒着判断是否合法
int x=0;
int y=0;
for(int i=len;i>=1;i--){
if(s[i]=='(') x++;
else y++;
if(x>y) return;
}
}
if(flag) b[right - left]++;
else a[left - right]++;
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%s", str + 1);
check(str);
}
ll ans = a[0]*a[0];
for(int i = 1; i <= 3e5; i++) ans += a[i] * b[i];
cout << ans << endl;
return 0;
}
//网上大神的代码,思路要比我的清晰一点
#include <bits/stdc++.h>
using namespace std;
int n;
typedef long long ll;
const int maxn = 3e5 + 5;
ll a[maxn], b[maxn];
char str[maxn];
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%s", str + 1);
int len = strlen(str + 1);
int left = 0;
int right = 0;
for(int i = 1; i <= len; i++) {//注意这里
if(str[i] == '(') left++;
else {
if(left) left--;
else right++;
}
}
if(left == 0) b[right]++;
if(right == 0) a[left]++;
}
ll ans = 0;
for(int i = 0; i <= 3e5; i++ ) ans += a[i] * b[i];
printf("%I64d\n", ans);
return 0;
}