codeforces 1303E

題目鏈接

題意

有一個字符串s,和一個字符串t,問可不可以將t分爲前後兩個部分,使得每個部分都對應一個s中的子序列,且這兩個子序列不相交。

數據範圍

字符串總長<=400

解法

首先有一個naive的O(n4)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(n4/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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章