/*
给两个括号序列,用一个合法的括号串来覆盖这两个串,求出这个最短串
这个问题可以分解成两个条件:
1.用一个最短的括号序列来覆盖这两个串
2.这个序列要合法
首先考虑第一个条件:
不难想到用两个状态dp[i,j]来表示匹配s[1..i],t[1..j]时的最短长度
转移也很简单:初始状态dp[0,0]=0,后面加'(',后面加')':都分别取更新对应状态
最后的结果是dp[lens,lent]
然后再来考虑上第二个条件
括号序列合法的条件是所有的前缀和>=0,且最后的和是0(懂我意思吧)
要让最后的串满足这个条件,我们必须在转移时考虑到前缀和状态,这个状态>=0,
自然想到升一维dp,dp[i,j,k]来表示匹配到s[1..i],t[1..j]且前缀和是k的最短长度
初始状态dp[0,0,0]=0,转移同上
这个前缀和的范围必定在[0,lens+lent],所以整个dp的复杂度是O(n^3)
最后的答案:
dp[i,j,k]+k里找个最小的记为mink
由于要输出解法,所以我们记下前驱即可(这都是细枝末节的实现了)
*/
#include<bits/stdc++.h>
using namespace std;
#define N 1005
char s[N],t[N];
int dp[205][205][405],lens,lent;
struct Node{
int i,j,k,flag,len;
Node(){}
Node(int i,int j,int k,int flag,int len):i(i),j(j),k(k),flag(flag),len(len){}
}pre[205][205][405];
stack<char>stk;
void print(Node node){
if(node.flag==-1)stk.push(')');
else if(node.flag==1)stk.push('(');
if(node.len)
print(pre[node.i][node.j][node.k]);
}
int main(){
scanf("%s%s",s+1,t+1);
lens=strlen(s+1);lent=strlen(t+1);
memset(dp,0x3f,sizeof dp);
dp[0][0][0]=0;
for(int i=0;i<=lens;i++)
for(int j=0;j<=lent;j++)
for(int k=0;k<=lens+lent;k++){
if(dp[i][j][k]==0x3f3f3f3f)continue;
if(k){//加个右括号
int f1,f2;
if(s[i+1]==')')f1=1;
else f1=0;
if(t[j+1]==')')f2=1;
else f2=0;
if(dp[i][j][k]+1<dp[i+f1][j+f2][k-1]){//更新状态
Node node=Node(i,j,k,-1,dp[i][j][k]);
pre[i+f1][j+f2][k-1]=node;
dp[i+f1][j+f2][k-1]=dp[i][j][k]+1;
}
}
//加个左括号
int f1,f2;
if(s[i+1]=='(')f1=1;
else f1=0;
if(t[j+1]=='(')f2=1;
else f2=0;
if(dp[i][j][k]+1<dp[i+f1][j+f2][k+1]){//更新状态
Node node=Node(i,j,k,1,dp[i][j][k]);
pre[i+f1][j+f2][k+1]=node;
dp[i+f1][j+f2][k+1]=dp[i][j][k]+1;
}
}
int Min=0x3f3f3f3f,mink=0;
for(int k=1;k<=lens+lent;k++){
if(dp[lens][lent][k]+k<dp[lens][lent][mink]+mink){
mink=k;
}
}
for(int i=1;i<=mink;i++)stk.push(')');
print(pre[lens][lent][mink]);
while(stk.size()){
cout<<stk.top();
stk.pop();
}
puts("");
}