<Codeforces 990C>
題意:
給n個只由 '(' 和 ')' 組成的串,問從這些串中選出兩個串,使他們括號匹配,能夠成多少個匹配串,自身和自身組合匹配也算。以題中第二個樣例說明:
輸入:2 ( ) ( )
輸出:4
解釋:輸入的兩個串 a,b 分別是 a: ( ),b: ( ),所以共四種連接方式,即 a->a,a->b,b->a,b->b
思路:
說實話,這個思路,就是一種只可意會不可言傳的感覺,我大概用我拙劣的語言,表述一下 T^T
我先對每個輸入進來的串,進行如下操作:
int ln = s.length();
for(int j = 0; j < ln; j++) {
if(s[j] == '(') l++;
else {
if(l) l--;
else r++;
}
}
這裏的 l 代表,在輸入進來的這個串中,不能與自身右括號形成匹配的左括號的個數;
r 則代表,在輸入進來的這個串中,不能與自身左括號形成匹配的右括號的個數。
我已經進我最大努力表述了,自行腦補一下這裏有一個笑哭的表情。。。注意聽~
這樣每個串無法在自身形成匹配的左右括號數就分別找出來了。
然後進行如下兩步操作:
if(!l) R[r]++;
if(!r) L[l]++;
以上兩步是核心代碼,我盡我最大努力解釋清楚,
首先明確兩點,
(1)如果某個串裏 l != 0 && r != 0,那這個串沒法和任何一個串進行匹配
(2)有且僅有 x 個左括號不能在自身匹配的串, 它要想配對, 必須找有且僅有 x 個右括號不能在自身匹配的串
這也就是L[ ], R[ ]這兩個數組的作用,如果 l == 0,那就意味着,這個串裏有且僅有 r 個右括號匹配不到 ( r 可以取0),這樣,它就必須找一個,有且僅有 r 個左括號匹配不到的的串,進行匹配。所以我在 l == 0 時,進行R[r]++,就是爲了找到一個L[r]和當前的R[r]進行相乘再加入ans裏,L[ ],R[ ]數組分別代表的值是僅有左括號不匹配,和僅有右括號不匹配的串的個數,而L[i], R[i]中的 i 值,則分別代表不匹配的左右括號各有幾個。r == 0 同理。
本人AC代碼:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <string>
#include <queue>
#include <set>
#include <map>
#include <stack>
#include <ctime>
#include <cctype>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 3e5 + 7;
const int Inf = 1e9 + 7;
pair <int, int> a[maxn];
queue <int> qua;
set <int> sst;
vector <int> vect;
map <int, int> mp;
priority_queue < int, vector<int>, less<int> > qua1;
priority_queue < int, vector<int>, greater<int> > qua2;
int n;
string s;
ll L[maxn], R[maxn]; //有pos個左括號不能在自身匹配的串, 它要想配對, 必須找有pos個右括號不能在自身匹配的串
// 而L[pos]和R[pos]記錄的就是左右括號與自身不匹配的串的個數, 即ans += L[pos] * R[pos]
ll ans;
int main() {
cin >> n;
int l, r; //記錄每個串中左、右括號無法在該串自身內進行匹配的個數分別爲多少
for(int i = 1; i <= n; i++) {
cin >> s;
l = r = 0;
int ln = s.length();
for(int j = 0; j < ln; j++) {
if(s[j] == '(') l++;
else {
if(l) l--;
else r++;
}
}
if(!l) R[r]++;
if(!r) L[l]++;
}
for(int i = 1; i <= maxn; i++) ans += L[i] * R[i];
ans += L[0] * R[0]; //自身就匹配的串的個數
cout << ans << endl;
}