CF49E Common ancestor 区间DP

题意:

戳这里

分析:

看错题意了,导致我一直认为有一种 \((n^2k)\) 的做法/kk

  • 正解:

    我们发现,公共祖先的每一个字母,一定对应着最终串的一段连续的区间,所以我们反向构造,利用区间DP反推出这段区间对应的字母,然后找出最短的一种

    具体来说就是:

    我们记 \(f_{i,j,k}\) 表示第 \(i\) 到第 \(j\) 个字母对应的区间能否变成 \(k\),转移就是 f[l][r][k]|=f[l][mid][x]&&f[mid+1][r][y]&&trans[x][y]==k,但是我们发现这样枚举的复杂度是 \(O(n^326^3)\) ,大部分枚举的字母无法转移,所以我们把枚举字母优化掉,直接提前存一下每个字母对应的转移,这样复杂度是 \(O(n^426)\)

    得到区间信息后我们考虑怎么得到答案,我们记 \(g_{x,y}\) 表示第一个串枚举到 \(x\) 第二个串枚举到 \(y\) 时的最小代价,转移:if(f1[x][i][c]==f2[y][j][c]) g[i][j]=min(g[i][j],g[x-1][y-1]+1)

代码:

#include<bits/stdc++.h>
#define pii pair<int,int>
#define mk(x,y) make_pair(x,y)
#define lc rt<<1
#define rc rt<<1|1
#define pb push_back
#define fir first
#define sec second
#define inl inline
#define reg register

using namespace std;

namespace zzc
{
	typedef long long ll;
	inline int read()
	{
		int x=0,f=1;char ch=getchar();
		while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
		while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
		return x*f;
	}
	
	int n;
	bool f[2][55][55][26];
	int g[55][55],s[2][55],length[2];
	char ch[55];
	vector<pii> c[26];
	
	void work()
	{
		for(int id=0;id<=1;id++) { scanf("%s",ch+1);n=strlen(ch+1);length[id]=n;for(int i=1;i<=n;i++) s[id][i]=ch[i]-'a';}
		n=read();
		for(int i=1;i<=n;i++)
		{
			scanf("%s",ch+1);
			c[ch[1]-'a'].pb(mk(ch[4]-'a',ch[5]-'a'));
		}
		
		for(int id=0;id<=1;id++)
		{
			for(int i=1;i<=length[id];i++) f[id][i][i][s[id][i]]=true;
			for(int len=1;len<=length[id];len++)
				for(int l=1,r;l+len-1<=length[id];l++)
				{
					r=l+len-1;
					for(int mid=l;mid<r;mid++) for(int k=0;k<=25;k++) for(auto x:c[k]) 
					f[id][l][r][k]|=(f[id][l][mid][x.fir]&&f[id][mid+1][r][x.sec]);
				}
		}
	
		memset(g,0x3f,sizeof(g));
		g[0][0]=0;
		for(int i=1;i<=length[0];i++) for(int j=1;j<=length[1];j++) for(int x=1;x<=i;x++) for(int y=1;y<=j;y++) for(int k=0;k<=25;k++) 
		if(f[0][x][i][k]&&f[1][y][j][k]) g[i][j]=min(g[i][j],g[x-1][y-1]+1);
	
		if(g[length[0]][length[1]]>50) g[length[0]][length[1]]=-1; 
		printf("%d\n",g[length[0]][length[1]]);
	}

}

int main()
{
	zzc::work();
	return 0;
}

posted @ 2021-01-21 15:23  youth518  阅读(92)  评论(0编辑  收藏  举报