bzoj 2121 字符串游戏

来源:互联网 发布:win10如何关闭端口 编辑:程序博客网 时间:2024/06/01 10:12
BX正在进行一个字符串游戏,他手上有一个字符串L,以及其他一些字符串的集合S,然后他可以进行以下操作:对于一个在集合S中的字符串p,如果p在L中出现,BX就可以选择是否将其删除,如果删除,则将删除后L分裂成的左右两部分合并。举个例子,L='abcdefg' , S={'de'},如果BX选择将'de'从L中删去,则删后的L='abcfg'。现在BX可以进行任意多次操作(删的次数,顺序都随意),他想知道最后L串的最短长度是多少。
f[i][j][k][p]表示i到j是否可以表示第k个字符串的前p个字符。
c[i][j]表示i到j是否可以全部删去。
有两种转移‘
f[j-1][k][p-1]&&st[k][p]==S[j]
f[d][k][p]&&c[d+1][j]
类似区间dp的东西可以采用固定一端,枚举另一端的方法

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>

#define ll long long
#define inf 1e9
#define eps 1e-10
#define md
#define N
using namespace std;
bool f[170][35][25],c[170][170];
int dp[170],len[35];
char S[170],st[35][25];
int main()
{
scanf("%s",S+1); int lth=strlen(S+1);
int n;
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%s",st[i]+1);
len[i]=strlen(st[i]+1);
}
for (int i=lth;i;i--)
{
memset(f,0,sizeof(f));
for (int k=1;k<=n;k++)
f[i-1][k][0]=1;
for (int j=i;j<=lth;j++)
{
for (int k=1;k<=n;k++)
for (int p=1;p<=len[k];p++)
f[j][k][p]|=(f[j-1][k][p-1]&&st[k][p]==S[j]);
for (int d=i;d<=j;d++)
if (c[d+1][j])
{
for (int k=1;k<=n;k++)
for (int p=1;p<=len[k];p++)
f[j][k][p]|=f[d][k][p];
}
}
for (int j=i;j<=lth;j++)
for (int k=1;k<=n;k++)
c[i][j]|=f[j][k][len[k]];
}
for (int i=1;i<=lth;i++)
{
dp[i]=dp[i-1]+1;
for (int j=1;j<=i;j++)
if (c[j][i]) dp[i]=min(dp[i],dp[j-1]);
}
printf("%d\n",dp[lth]);
return 0;
}

0 0
原创粉丝点击