codeforces 1303E

题目链接

题意

有一个字符串s,和一个字符串t,问可不可以将t分为前后两个部分,使得每个部分都对应一个s中的子序列,且这两个子序列不相交。

数据范围

字符串总长<=400

解法

首先有一个naive的 O ( n 4 ) O(n^4) 解法,设dp状态f[i][j][k]表示考虑到s串的第i个字符,t的前半部分考虑到的位置为j,后半部分考虑到的位置为k的状态是否可行,然后需要枚举前半部分的总长。
考虑优化这个做法,发现dp转移全是01,考虑能否用bitset优化这个做法:首先考虑前半部分的转移, f [ i + 1 ] [ j + 1 ] [ k ] = ( s [ i + 1 ] = = t [ j + 1 ] ) f [ i ] [ j ] [ k ] f[i+1][j+1][k]=(s[i+1]==t[j+1])*f[i][j][k] ,可以发现此时与k没什么关系,所以直接bitset就行,然后是后半部分的转移: f [ i + 1 ] [ j ] [ k + 1 ] = ( s [ i + 1 ] = = t [ k + 1 ] ) f [ i ] [ j ] [ k ] f[i+1][j][k+1]=(s[i+1]==t[k+1])*f[i][j][k] 这里由于我们需要枚举k,所以这里的转移需要一个额外的bitset记录前面的判别式,具体可以看代码
复杂度 O ( n 4 / w ) O(n^4/w)

#include<bits/stdc++.h>
using namespace std;
const int maxn=405;
inline int read(){
	char c=getchar();int t=0,f=1;
	while((!isdigit(c))&&(c!=EOF)){if(c=='-')f=-1;c=getchar();}
	while((isdigit(c))&&(c!=EOF)){t=(t<<3)+(t<<1)+(c^48);c=getchar();}
	return t*f;
}
int T,n,m;
bitset<maxn> f[maxn][maxn],alfa[maxn];
char s[maxn],t[maxn];
signed main(){
	//freopen("5.in","r",stdin);
	//freopen("5.out","w",stdout);
	T=read();
	while(T--){
		for(int i=1;i<=n;i++)alfa[i].reset();
		scanf("%s",s+1);
		scanf("%s",t+1);
		n=strlen(s+1);
		m=strlen(t+1);
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++){
				if(s[i]==t[j])alfa[i][j]=1;
			}
		}
		int ans=0;
		for(int k=1;k<=m;k++){//这里的k和题解中的k不是一个意思,这里枚举的是前后部分的分界点(题解中的k并没有被枚举)
			f[0][0][k]=1;
			for(int i=0;i<=n;i++){
				for(int j=0;j<=k;j++){
					f[i+1][j]|=f[i][j];
					if(s[i+1]==t[j+1]){
						f[i+1][j+1]|=f[i][j];
					}
					f[i+1][j]|=(f[i][j]<<1)&(alfa[i+1]);//这里就是转移后面部分的方程
				}
			}
			//printf("%d\n",k);
			if(f[n][k][m]==1){
				//printf("%d\n",k);
				for(int i=0;i<=n;i++){
					for(int j=0;j<=k;j++){
						f[i][j].reset();
					}
				}
				ans=1;break;
			}
			for(int i=0;i<=n;i++){
				for(int j=0;j<=k;j++){
					f[i][j].reset();
				}
			}
		}
		if(ans)puts("YES");
		else puts("NO");
	}
	return 0;
}
发布了95 篇原创文章 · 获赞 9 · 访问量 3188

猜你喜欢

转载自blog.csdn.net/wmhtxdy/article/details/104343611