Bracket Groups:赛时猜出来用 ACAM,结果没猜到结论,我是糖比。
首先判掉一些 corner,如果出现了 \(\texttt{()}\) 为单个字符串,则一定无解。
发现后面不太好做,所以可以套路地猜一猜答案上界,发现最多只需要分成两组。具体地,考虑往极端情况构造,弄出下面两种括号串:
- \(\texttt{((((((} \cdots\texttt{))))))}\)。
- \(\texttt{()()()} \cdots\texttt{()()()}\)。
考虑证明,如果 \(s\) 不是这两个串中任意一个串的子串,则放哪一组都可以。如果 \(s\) 为第一个串的子串,那么 \(s\) 中一定含有两个相同且相邻的字符(一种 corner 是 \(\texttt{)(}\) 的情况,此时也会放到第一组),而这是不可能出现在第二个串中的。如果 \(s\) 为第一个串的子串则也是同理的。
剩下的只需要考虑能否被一个括号串全部包含即可。这是个经典的 ACAM 上 DP 的问题。\(dp_{i, j, k}\) 表示考虑到第 \(i\) 个字符,括号串前缀和为 \(j\),ACAM 上在节点 \(k\) 处是否可行,然后转移的时候记录一下前驱即可。最后反过来搜一遍构造出方案。
时间复杂度 \(O(nk^3)\)。
#include <bits/stdc++.h>
#define fi first
#define se second
#define eb(x) emplace_back(x)
#define pb(x) push_back(x)
#define lc(x) (tr[x].ls)
#define rc(x) (tr[x].rs)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
using pi = pair<int, int>;
const int N = 55, V = 3005;
int n, m, ch[V][2], idx, tag[V], ne[V];
int s[N][N], slen[N];
char ts[N];
void insert(int id)
{int p = 0;for(int i = 1; i <= slen[id]; i++){if(ch[p][s[id][i]] == 0) ch[p][s[id][i]] = ++idx;p = ch[p][s[id][i]];}tag[p] = 1;
}
vector<int> g[V];
void dfs(int u)
{for(auto v : g[u]){tag[v] |= tag[u];dfs(v);}
}
void build()
{queue<int> q;for(int i = 0; i < 2; i++){if(ch[0][i]) q.push(ch[0][i]);}while(!q.empty()){int u = q.front();q.pop();for(int i = 0; i < 2; i++){int v = ch[u][i];if(v) { ne[v] = ch[ne[u]][i]; q.push(v); }else ch[u][i] = ch[ne[u]][i];}}for(int i = 1; i <= idx; i++) g[ne[i]].push_back(i);dfs(0);
}
bitset<V> dp[N][N];
tuple<int, int, int> pre[N][N][V];
char ans[N];
vector<int> ans2, ans3;
void construct(int p)
{int i = m, j = 0;while(i){tuple<int, int, int> tmp = pre[i][j][p];ans[i] = (get<1>(tmp) - j > 0 ? ')' : '(');j = get<1>(tmp);p = get<2>(tmp);i--;}cout << 1 << "\n";cout << ans + 1 << "\n";cout << n << "\n";for(int i = 1; i <= n; i++) cout << i << " ";
}
int main()
{//freopen("sample.in", "r", stdin);//freopen("sample.out", "w", stdout);ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin >> n >> m;for(int i = 1; i <= n; i++){cin >> ts + 1;slen[i] = strlen(ts + 1);if(slen[i] == 2 && ts[1] == '(' && ts[2] == ')'){cout << "-1";return 0;}for(int j = 1; j <= slen[i]; j++)s[i][j] = (ts[j] == '(' ? 1 : 0);insert(i);}build();dp[0][0][0] = 1;for(int i = 0; i < m; i++)for(int j = 0; j <= m; j++)for(int k = 0; k <= idx; k++){if(dp[i][j][k] == 0) continue;if(tag[ch[k][0]] == 0 && j - 1 >= 0){dp[i + 1][j - 1][ch[k][0]] = 1;pre[i + 1][j - 1][ch[k][0]] = {i, j, k};}if(tag[ch[k][1]] == 0){dp[i + 1][j + 1][ch[k][1]] = 1;pre[i + 1][j + 1][ch[k][1]] = {i, j, k};} }for(int i = 0; i <= idx; i++){if(dp[m][0][i]){construct(i);return 0;}}cout << "2\n";for(int i = 1; i <= m; i++) {if(i & 1) cout << "(";else cout << ")";}cout << "\n";for(int i = 1; i <= n; i++){int mn = 0, mx = 0, now = 0;for(int j = 1; j <= slen[i]; j++){if(s[i][j] == 0) now--;else now++;mn = min(mn, now);mx = max(mx, now);}if(mx - mn >= 2) ans2.push_back(i);else ans3.push_back(i);}cout << ans2.size() << "\n";for(auto itm : ans2) cout << itm << " ";cout << "\n";for(int i = 1; i <= m / 2; i++) cout << "(";for(int i = 1; i <= m / 2; i++) cout << ")";cout << "\n";cout << ans3.size() << "\n";for(auto itm : ans3) cout << itm << " ";cout << "\n"; return 0;
}