#include <bits/stdc++.h> using namespace std; using LL = long long; #define FOR(i, l, r) for (auto i = (l); i <= (r); ++i) #define REP(i, n) FOR (i, 0, (n)-1) #define ssize(x) int(x.size()) template<class A, class B> auto& operator<<(ostream& o, pair<A, B> p) { return o << "(" << p.first << ", " << p.second << ")"; } template<class T> auto operator<<(ostream& o, T x) -> decltype(x.end(), o) { o << "{"; int i = 0; for (auto e : x) o << (", ") + 2 * !i++ << e; return o << "}"; } #ifdef DEBUG #define debug(x...) \ cerr << "[" #x "]: ", [](auto... $) { ((cerr << $ << "; "), ...); }(x), \ cerr << '\n' #else #define debug(...) \ { \ } #endif #define MAX numeric_limits<int>::max() int n, k; string seq; vector<int> possible_seps; int best_score = MAX; void input(); void backtrack(int last_sep = -1, int score = 0, int sepssofar = 0); int index(string::iterator first, string::iterator last); int main() { cin.tie(0)->sync_with_stdio(0); input(); // Backtrack backtrack(); // Output cout << best_score << "\n"; return 0; } void backtrack(int last_sep, int score, int sepssofar) { // last_sep --- position in possible_seps of last separator // score --- sum of the substring indexes accumulated so far // sepssofar --- number of separators used so far int last_pos = (last_sep == -1 ? -1 : possible_seps[last_sep]); // Check whether it's possible to fit with seps if (possible_seps.size() - last_sep < k - sepssofar) return; // Check whether we have arrived to the end if (sepssofar + 1 == k) { best_score = min(best_score, score + index(seq.begin() + 1 + last_pos, seq.end())); return; } // Backtrack FOR (sep, last_sep + 1, possible_seps.size() - 1) backtrack(sep, score + index(seq.begin() + 1 + last_pos, seq.begin() + possible_seps[sep] + 1), sepssofar + 1); } int index(string::iterator first, string::iterator last) { debug((string){first, last}.c_str()); int ans = 0; int depth = 0; vector<int> dp; dp.reserve(last - first + 1); dp.push_back(0); FOR (it, first, last - 1) { if (*it == '(') { depth++; dp.push_back(0); } else { // We are exiting balanced substring if (depth == 0) { while (it + 1 < last && *(it + 1) == ')') ++it; dp[0] = 0; continue; } dp.pop_back(); ans++; ans += dp.back(); dp.back()++; depth--; } } return ans; } void input() { cin >> n >> k >> seq; // Find all "()" because only them we possibly want to have split. REP (i, n - 1) if (seq[i] == '(' && seq[i + 1] == ')') possible_seps.push_back(i); k = min(k, (int)possible_seps.size() + 1); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | #include <bits/stdc++.h> using namespace std; using LL = long long; #define FOR(i, l, r) for (auto i = (l); i <= (r); ++i) #define REP(i, n) FOR (i, 0, (n)-1) #define ssize(x) int(x.size()) template<class A, class B> auto& operator<<(ostream& o, pair<A, B> p) { return o << "(" << p.first << ", " << p.second << ")"; } template<class T> auto operator<<(ostream& o, T x) -> decltype(x.end(), o) { o << "{"; int i = 0; for (auto e : x) o << (", ") + 2 * !i++ << e; return o << "}"; } #ifdef DEBUG #define debug(x...) \ cerr << "[" #x "]: ", [](auto... $) { ((cerr << $ << "; "), ...); }(x), \ cerr << '\n' #else #define debug(...) \ { \ } #endif #define MAX numeric_limits<int>::max() int n, k; string seq; vector<int> possible_seps; int best_score = MAX; void input(); void backtrack(int last_sep = -1, int score = 0, int sepssofar = 0); int index(string::iterator first, string::iterator last); int main() { cin.tie(0)->sync_with_stdio(0); input(); // Backtrack backtrack(); // Output cout << best_score << "\n"; return 0; } void backtrack(int last_sep, int score, int sepssofar) { // last_sep --- position in possible_seps of last separator // score --- sum of the substring indexes accumulated so far // sepssofar --- number of separators used so far int last_pos = (last_sep == -1 ? -1 : possible_seps[last_sep]); // Check whether it's possible to fit with seps if (possible_seps.size() - last_sep < k - sepssofar) return; // Check whether we have arrived to the end if (sepssofar + 1 == k) { best_score = min(best_score, score + index(seq.begin() + 1 + last_pos, seq.end())); return; } // Backtrack FOR (sep, last_sep + 1, possible_seps.size() - 1) backtrack(sep, score + index(seq.begin() + 1 + last_pos, seq.begin() + possible_seps[sep] + 1), sepssofar + 1); } int index(string::iterator first, string::iterator last) { debug((string){first, last}.c_str()); int ans = 0; int depth = 0; vector<int> dp; dp.reserve(last - first + 1); dp.push_back(0); FOR (it, first, last - 1) { if (*it == '(') { depth++; dp.push_back(0); } else { // We are exiting balanced substring if (depth == 0) { while (it + 1 < last && *(it + 1) == ')') ++it; dp[0] = 0; continue; } dp.pop_back(); ans++; ans += dp.back(); dp.back()++; depth--; } } return ans; } void input() { cin >> n >> k >> seq; // Find all "()" because only them we possibly want to have split. REP (i, n - 1) if (seq[i] == '(' && seq[i + 1] == ')') possible_seps.push_back(i); k = min(k, (int)possible_seps.size() + 1); } |