bzoj 2121: 字符串游戲

題目大意:給你一個大字符串和一個字符串的集合,每次可以從字符串的集合中選出一個,如果那個大字符串中包含了這個字符串,就可以從大串中將小串刪掉,刪完後兩邊接起來,求刪完後大串最少剩幾個字符     大串<=150,小串<=20,小串個數<=30


這題沒想着怎麼做,主要還是太弱了。。。

首先可以設f[i][j][k][l]代表第i個到第j個能否刪成第k個小串的前l個字符

那麼當S[j]==s[k][l] 且 f[i][j-1][k][l-1] 時可以f[i][j][k][l]=1,當c[j][k]時,可以f[i][k][x][l]|=f[i][j-1][x][l]    c[j][k]代表j~k可以全部刪完

然後最後的統計就很簡單了,不過因爲是bool所以可以壓位,即把f[i][j][k][l]壓成f[i][j][l],k用二進制表示,這樣可以加快速度



不壓位的

#include<cstdio>
#include<cstring>
#include<cassert>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=161,maxm=37,maxl=27;
int q,n,m,len[maxm]; char S[maxn],s[maxm][maxl];
void init(){
	scanf("%s%d",S+1,&m); n=strlen(S+1); q=0;
	for (int i=1;i<=m;++i) scanf("%s",s[i]+1),len[i]=strlen(s[i]+1),q=max(q,len[i]);
}
bool f[maxn][maxm][maxl]; bool c[maxn][maxn];
void getc(){
	for (int i=n;i>=1;--i){
		memset(f,0,sizeof(f)); for (int j=1;j<=m;++j) f[i-1][j][0]=1;
		for (int j=i;j<=n;++j){
			for (int k=1;k<=m;++k) for (int l=1;l<=len[k];++l)
				if (s[k][l]==S[j] && f[j-1][k][l-1]) f[j][k][l]=1;


			for (int k=j;k<=n;++k) if(c[j][k])
				for (int x=1;x<=m;++x) for (int l=0;l<=q;++l)
					f[k][x][l]|=f[j-1][x][l];
			
		}
		for (int j=i;j<=n;++j) for (int k=1;k<=m;++k) if (f[j][k][len[k]]) c[i][j]=1;
	}
}
int ans[maxn];
void work(){
	getc(); ans[0]=0;
	for (int i=1;i<=n;++i){
		ans[i]=ans[i-1]+1;
		for (int j=1;j<=i;++j) if (c[j][i]) ans[i]=min(ans[i],ans[j-1]);
	}
	printf("%d\n",ans[n]);
}
int main(){
	init();
	work();
	return 0;
}



壓位的

#include<cstdio>
#include<cstring>
#include<cassert>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=161,maxm=37,maxl=27;
int q,n,m,len[maxm]; char S[maxn],s[maxm][maxl];
void init(){
	scanf("%s%d",S+1,&m); n=strlen(S+1); q=0;
	for (int i=1;i<=m;++i) scanf("%s",s[i]+1),len[i]=strlen(s[i]+1),q=max(q,len[i]);
}
int f[maxn][maxl],fd[4321]; bool c[maxn][maxn];
void getc(){
	for (int i=0;i<=m;++i) fd[(1<<i)%4321]=i;
	for (int i=n;i>=1;--i){
		memset(f,0,sizeof(f)); f[i-1][0]=(1<<(m+1))-1;
		for (int j=i;j<=n;++j){
			for (int l=1;l<=q;++l) for (int x=f[j-1][l-1];x;x-=x&(-x)){
				int k=fd[(x&(-x))%4321]; if (s[k][l]==S[j]) f[j][l]|=1<<k;
			}
			for (int k=j;k<=n;++k) if (c[j][k])
				for (int l=0;l<=q;++l) f[k][l]|=f[j-1][l];
		}
		for (int j=i;j<=n;++j) for (int k=1;k<=m;++k)
			if ((f[j][len[k]]>>k)&1) {c[i][j]=1; break;}
	}
}
int ans[maxn];
void work(){
	getc(); ans[0]=0;
	for (int i=1;i<=n;++i){
		ans[i]=ans[i-1]+1;
		for (int j=1;j<=i;++j) if (c[j][i]) ans[i]=min(ans[i],ans[j-1]);
	}
	printf("%d\n",ans[n]);
}
int main(){
	init();
	work();
	return 0;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章