不想再碰第二次的题目。
首先我们需要对正则表达式建出对应的
ϵ
−
N
F
A
\epsilon-NFA
ϵ−NFA,这个就按正常的正则表达式解析就行。这里
ϵ
−
N
F
A
\epsilon-NFA
ϵ−NFA上的每条转移弧长度是
0
0
0(
ϵ
\epsilon
ϵ)或
1
1
1(字符)。
不过我第一次写,出了一堆问题。这里的正则表达式允许空串,于是有可能出现连续的运算符。同时我按lrj书上介绍的方法把一些点合并了,然后WA爆了,不知道是我实现错了还是确实不可以,最后改成暴力做法才过。
接着考虑怎么解决原问题。显然直接DP即可,令
f
i
,
j
f_{i,j}
fi,j表示现在已经匹配了
S
S
S的前
i
i
i位,在
ϵ
−
N
F
A
\epsilon-NFA
ϵ−NFA上的状态
j
j
j的最短可能长度,这里要求若
1
<
i
<
∣
S
∣
1<i<|S|
1<i<∣S∣,下一次必须匹配到
i
+
1
i+1
i+1。这里的转移图由于有
0
0
0权边,因此不能直接DP,需要
01
01
01边权BFS。
这个做法时间复杂度为
O
(
∣
S
∣
∣
E
∣
)
\mathcal O(|S||E|)
O(∣S∣∣E∣),可以在时限内通过。
但这题的空间限制比较紧,无法直接储存DP状态。注意到
i
i
i这一维可以分层BFS,因此可以滚动数组。但这里还要输出方案,我的解决方法比较取巧:我们只记录
i
=
0
i=0
i=0和
i
=
∣
S
∣
i=|S|
i=∣S∣时的转移,而对于中间的
i
i
i,由于最终一定是经过原来的
S
S
S串,因此我们只需要记录
i
=
0
i=0
i=0时的最后一个状态编号,这显然可以滚动数组。这样空间复杂度就降到了
O
(
∣
S
∣
+
∣
E
∣
)
\mathcal O(|S|+|E|)
O(∣S∣+∣E∣)。
#include <bits/stdc++.h>
#define FR first
#define SE second
#define inf 0x3f3f3f3f
using namespace std;
typedef pair<int,int> pr;
vector <pr> e[50005];
int st1[50005],top1,top2,sz;
pr st2[50005];
int bound[50005];
void insert() {
if (st1[top1]==1) {
pr u,v;
if (top2&&bound[top2]==top1) v=st2[top2--];
else {
sz+=2;
e[sz-1].push_back(pr(sz,0));
v=pr(sz-1,sz);
}
if (top2&&bound[top2]==top1-1) u=st2[top2--];
else {
sz+=2;
e[sz-1].push_back(pr(sz,0));
u=pr(sz-1,sz);
}
sz+=2;
e[sz-1].push_back(pr(u.FR,0));
e[sz-1].push_back(pr(v.FR,0));
e[u.SE].push_back(pr(sz,0));
e[v.SE].push_back(pr(sz,0));
st2[++top2]=pr(sz-1,sz);
bound[top2]=top1-1;
}
else if (st1[top1]==2) {
pr u,v;
if (top2&&bound[top2]==top1) v=st2[top2--];
else {
sz+=2;
e[sz-1].push_back(pr(sz,0));
v=pr(sz-1,sz);
}
if (top2&&bound[top2]==top1-1) u=st2[top2--];
else {
sz+=2;
e[sz-1].push_back(pr(sz,0));
u=pr(sz-1,sz);
}
sz+=2;
e[sz-1].push_back(pr(u.FR,0));
e[u.SE].push_back(pr(v.FR,0));
e[v.SE].push_back(pr(sz,0));
st2[++top2]=pr(sz-1,sz);
bound[top2]=top1-1;
}
else {
pr u;
if (top2&&bound[top2]==top1-1) u=st2[top2--];
else {
sz+=2;
e[sz-1].push_back(pr(sz,0));
u=pr(sz-1,sz);
}
sz+=2;
//SETS::merge(u.FR,u.SE);
e[sz-1].push_back(pr(u.FR,0));
e[u.SE].push_back(pr(u.FR,0));
e[u.FR].push_back(pr(u.SE,0));
e[u.SE].push_back(pr(sz,0));
st2[++top2]=pr(sz-1,sz);
bound[top2]=top1-1;
}
top1--;
}
pr build(char *s,int n) {
for(int i=1;i<=n;i++) {
if (i>1&&s[i]!=')'&&s[i]!='|'&&s[i]!='*'&&s[i-1]!='('&&s[i-1]!='|') {
while (top1&&st1[top1]>2&&st1[top1]<4)
insert();
st1[++top1]=2;
}
if (s[i]=='(') st1[++top1]=4;
else if (s[i]>='a'&&s[i]<='z') {
sz+=2;
e[sz-1].push_back(pr(sz,s[i]));
st2[++top2]=pr(sz-1,sz);
bound[top2]=top1;
}
else if (s[i]=='.') {
sz+=2;
e[sz-1].push_back(pr(sz,s[i]));
st2[++top2]=pr(sz-1,sz);
bound[top2]=top1;
}
else if (s[i]=='|') {
while (top1&&st1[top1]>1&&st1[top1]<4)
insert();
st1[++top1]=1;
}
else if (s[i]=='*') st1[++top1]=3;
else {
while (top1&&st1[top1]!=4)
insert();
if (top2&&bound[top2]>=top1) bound[top2]--;
top1--;
}
}
while (top1)
insert();
return pr(st2[1].FR,st2[1].SE);
}
int q[2][100005];
int head[30005],num[50005],num2[50005],nxt[50005];
void trans1(int *f,int *g,int *p) {
memset(head,0,sizeof(head));
memset(g,0x3f,sizeof(int)*(sz+1));
memset(p,0,sizeof(int)*(sz+1));
int maxn=0,tot=0;
for(int i=1;i<=sz;i++)
if (f[i]<inf) {
maxn=max(maxn,f[i]);
num[++tot]=i;
nxt[tot]=head[f[i]];
head[f[i]]=tot;
}
int *q1=q[0],*q2=q[1],len1=0,len2=0;
for(int i=0;i<=maxn||len2;i++) {
swap(q1,q2);
swap(len1,len2);
len2=0;
for(int j=head[i];j;j=nxt[j])
if (i<g[num[j]]) {
g[num[j]]=i;
q1[++len1]=num[j];
}
int l=1,r=len1;
while (l<=r) {
int x=q1[l++];
if (i>g[x]) continue;
for(int j=0;j<e[x].size();j++) {
int u=e[x][j].FR;
if (!e[x][j].SE) {
if (i<g[u]) {
g[u]=i;
p[u]=x;
q1[++r]=u;
}
}
else {
if (i+1<g[u]) {
g[u]=i+1;
p[u]=x;
q2[++len2]=u;
}
}
}
}
}
}
void trans2(int *f,int *g,int *p,char c) {
memset(head,0,sizeof(head));
memset(g,0x3f,sizeof(int)*(sz+1));
memset(p,0,sizeof(int)*(sz+1));
int maxn=0,tot=0;
for(int i=1;i<=sz;i++)
if (f[i]<inf) {
int v=f[i]+1;
for(int j=0;j<e[i].size();j++)
if (e[i][j].SE=='.'||e[i][j].SE==c) {
maxn=max(maxn,v);
num[++tot]=e[i][j].FR;
num2[tot]=i;
nxt[tot]=head[v];
head[v]=tot;
}
}
int *q1=q[0],*q2=q[1],len1=0,len2=0;
for(int i=0;i<=maxn||len2;i++) {
swap(q1,q2);
swap(len1,len2);
len2=0;
for(int j=head[i];j;j=nxt[j])
if (i<g[num[j]]) {
g[num[j]]=i;
p[num[j]]=num2[j];
q1[++len1]=num[j];
}
int l=1,r=len1;
while (l<=r) {
int x=q1[l++];
if (i>g[x]) continue;
for(int j=0;j<e[x].size();j++)
if (!e[x][j].SE&&i<g[e[x][j].FR]) {
int u=e[x][j].FR;
g[u]=i;
p[u]=p[x];
q1[++r]=u;
}
}
}
}
int p1[50005],p2[2][50005],p3[50005];
int f1[50005],f2[2][50005],f3[50005];
char s1[20005],s2[20005],ans[100005];
int main() {
freopen("expression.in","r",stdin);
freopen("expression.out","w",stdout);
scanf("%s%s",s1+1,s2+1);
int n=strlen(s1+1),m=strlen(s2+1);
pr t=build(s1,n);
int sx=t.FR,tx=t.SE;
memset(f3,0x3f,sizeof(f3));
f3[sx]=0;
trans1(f3,f1,p1);
int cur=0;
for(int i=1;i<=m;i++) {
cur^=1;
if (i>1) {
trans2(f2[cur^1],f2[cur],p2[cur],s2[i]);
int *p=p2[cur],*q=p2[cur^1];
for(int i=1;i<=sz;i++) p[i]=q[p[i]];
}
else trans2(f1,f2[cur],p2[cur],s2[i]);
}
trans1(f2[cur],f3,p3);
if (f3[tx]==inf) {
puts("NO");
return 0;
}
int sz=0,x=tx;
while (p3[x]) {
int u=p3[x];
for(int i=0;i<e[u].size();i++)
if (e[u][i].FR==x&&f3[u]+(e[u][i].SE>0)==f3[x]) {
if (e[u][i].SE>='a'&&e[u][i].SE<='z') ans[++sz]=e[u][i].SE;
else if (e[u][i].SE=='.') ans[++sz]='a';
break;
}
x=u;
}
for(int i=m;i>0;i--) ans[++sz]=s2[i];
x=p2[cur][x];
while (p1[x]) {
int u=p1[x];
for(int i=0;i<e[u].size();i++)
if (e[u][i].FR==x&&f1[u]+(e[u][i].SE>0)==f1[x]) {
if (e[u][i].SE>='a'&&e[u][i].SE<='z') ans[++sz]=e[u][i].SE;
else if (e[u][i].SE=='.') ans[++sz]='a';
break;
}
x=u;
}
reverse(ans+1,ans+sz+1);
puts(ans+1);
return 0;
}
/*
a(*)b
ab
*/