Codeforces gym 100531 E

不想再碰第二次的题目。
首先我们需要对正则表达式建出对应的 ϵ − 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(SE),可以在时限内通过。
但这题的空间限制比较紧,无法直接储存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
*/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值