#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
template <typename T>
using ordered_set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
#pragma GCC optimize("Ofast,unroll-loops")
#pragma GCC target("avx,avx2,sse,sse2")
#define mp make_pair
#define sz(x) (int)((x).size())
#define all(x) (x).begin(),(x).end()
#define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);}
#define eb emplace_back
#define sim template < class c
#define ris return * this
#define dor > debug & operator <<
#define eni(x) sim > typename \
enable_if<sizeof dud<c>(0) x 1, debug&>::type operator<<(c i) {
sim > struct rge { c b, e; };
sim > rge<c> range(c i, c j) { return rge<c>{i, j}; }
sim > auto dud(c* x) -> decltype(cerr << *x, 0);
sim > char dud(...);
struct debug {
#ifdef HOME
~debug() { cerr << endl; }
eni(!=) cerr << boolalpha << i; ris; }
eni(==) ris << range(begin(i), end(i)); }
sim, class b dor(pair < b, c > d) {
ris << "(" << d.first << ", " << d.second << ")";
}
sim dor(rge<c> d) {
*this << "[";
for (auto it = d.b; it != d.e; ++it)
*this << ", " + 2 * (it == d.b) << *it;
ris << "]";
}
#else
sim dor(const c&) { ris; }
#endif
};
#define imie(...) " [" << #__VA_ARGS__ ": " << (__VA_ARGS__) << "] "
const int DIM = 20;
const int MAX = 400'005;
char str[DIM][MAX];
int dp[1 << DIM][2], sum[1 << DIM], mnm[DIM];
int len[DIM], cnt[DIM], val[DIM][MAX * 2];
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
#ifdef HOME
freopen("test.in", "r", stdin);
freopen("test.out", "w", stdout);
#endif
int n; cin >> n;
for (int i = 0; i < n; ++i) {
cin >> (str[i] + 1);
int l = strlen(str[i] + 1);
len[i] = l;
int s = 0;
for (int j = 1; j <= l; ++j) {
s += (str[i][j] == '(' ? 1 : -1);
debug() << imie(s);
if (mnm[i] > s) {
mnm[i] = s;
cnt[i] = 1;
} else if (mnm[i] == s) {
++cnt[i];
}
if (mnm[i] == s)
++val[i][s + l];
}
sum[1 << i] = s;
}
memset(dp, -0x3f, sizeof(dp));
dp[0][true] = 0;
for (int msk = 1; msk < (1 << n); ++msk) {
int bb = (msk & -msk);
sum[msk] = sum[msk ^ bb] + sum[bb];
for (int b = 0; b < n; ++b) {
if (!(msk & (1 << b)))
continue;
int axm = (msk ^ (1 << b));
if (dp[axm][true] < 0)
continue;
if (sum[axm] + mnm[b] < 0) {
if (sum[axm] <= len[b])
dp[msk][false] = max(dp[msk][false], dp[axm][true] + val[b][-sum[axm] + len[b]]);
else
dp[msk][false] = max(dp[msk][false], dp[axm][true]);
} else {
if (sum[axm] + mnm[b] == 0)
dp[msk][true] = max(dp[msk][true], dp[axm][true] + cnt[b]);
else
dp[msk][true] = max(dp[msk][true], dp[axm][true]);
}
}
}
debug() << range(cnt, cnt + n);
debug() << range(mnm, mnm + n);
int ans = 0;
for (int msk = 1; msk < (1 << n); ++msk)
ans = max(ans, max(dp[msk][true], dp[msk][false]));
cout << ans;
return 0;
}
566. Reshape the Matrix | 167. Two Sum II - Input array is sorted |
387. First Unique Character in a String | 383. Ransom Note |
242. Valid Anagram | 141. Linked List Cycle |
21. Merge Two Sorted Lists | 203. Remove Linked List Elements |
733. Flood Fill | 206. Reverse Linked List |
83. Remove Duplicates from Sorted List | 116. Populating Next Right Pointers in Each Node |
145. Binary Tree Postorder Traversal | 94. Binary Tree Inorder Traversal |
101. Symmetric Tree | 77. Combinations |
46. Permutations | 226. Invert Binary Tree |
112. Path Sum | 1556A - A Variety of Operations |
136. Single Number | 169. Majority Element |
119. Pascal's Triangle II | 409. Longest Palindrome |
1574A - Regular Bracket Sequences | 1574B - Combinatorics Homework |
1567A - Domino Disaster | 1593A - Elections |
1607A - Linear Keyboard | EQUALCOIN Equal Coins |