BZOJ2121: 字符串游戏(DP)(字符串删单词,求最多可以删去多少)

时间:2023-03-09 03:51:59
BZOJ2121: 字符串游戏(DP)(字符串删单词,求最多可以删去多少)

2121: 字符串游戏

Time Limit: 10 Sec  Memory Limit: 259 MB
Submit: 672  Solved: 376
[Submit][Status][Discuss]

Description

BX正在进行一个字符串游戏,他手上有一个字符串L,以及其他一些字符串的集合S,然后他可以进行以下操作:对
于一个在集合S中的字符串p,如果p在L中出现,BX就可以选择是否将其删除,如果删除,则将删除后L分裂成的左右
两部分合并。举个例子,L='abcdefg' , S={'de'},如果BX选择将'de'从L中删去,则删后的L='abcfg'。现在BX可
以进行任意多次操作(删的次数,顺序都随意),他想知道最后L串的最短长度是多少。

Input

输入的第一行包含一个字符串,表示L。
第二行包含一个数字n,表示集合S中元素个数。
以下n行,每行一个字符串,表示S中的一个元素。
输入字符串都只包含小写字母。

Output

输出一个整数,表示L的最短长度。

Sample Input

aaabccd
3
ac
abc
aaa

Sample Output

2
【样例说明】
aaabccd
aacd
ad
对于100%数据,满足|L|<151,|S|<31,S中的每个元素|p|<21

HINT

Source

思路:我们用f[i][j][k][l]表示第[i,j]这个区间能否删成第k个单词的前l位,用cov[i][j]表示[i,j]这个区间能否被完全删去。

复杂度O(N^3*S*p);

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=;
int f[maxn][maxn][][],cov[maxn][maxn],dp[maxn];
char c[maxn],s[][]; int Len[];
int main()
{
int N,M;
scanf("%s",c+); N=strlen(c+);
scanf("%d",&M);
for(int i=;i<=M;i++){
scanf("%s",s[i]+);
Len[i]=strlen(s[i]+);
}
rep(i,,N) rep(j,,M) f[i][i-][j][]=; //匹配的时候需要边界条件
rep(len,,N)
rep(L,,N-len+){
int R=L+len-;
rep(i,,M){
rep(j,,Len[i]) if(c[R]==s[i][j]) f[L][R][i][j]|=f[L][R-][i][j-]; //匹配
rep(j,,Len[i]) rep(k,L+,R) //不匹配
f[L][R][i][j]|=(f[L][k-][i][j]&cov[k][R]);
}
rep(i,,M) cov[L][R]|=f[L][R][i][Len[i]];
}
rep(i,,N){ //背包得到最大值
rep(j,,i) if(cov[j][i]) rep(k,i,N) dp[k]=max(dp[k],dp[j-]+i-j+);
rep(j,i+,N) dp[j]=max(dp[j],dp[j-]);
}
printf("%d\n",N-dp[N]);
return ;
}

把int换成bool快了一倍,word天啦。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=;
bool f[maxn][maxn][][],cov[maxn][maxn];
char c[maxn],s[][];int Len[],dp[maxn];
int main()
{
int N,M;
scanf("%s",c+); N=strlen(c+);
scanf("%d",&M);
for(int i=;i<=M;i++){
scanf("%s",s[i]+);
Len[i]=strlen(s[i]+);
}
rep(i,,N) rep(j,,M) f[i][i-][j][]=; //匹配的时候需要边界条件
rep(len,,N)
rep(L,,N-len+){
int R=L+len-;
rep(i,,M){
rep(j,,Len[i]) if(c[R]==s[i][j]) f[L][R][i][j]|=f[L][R-][i][j-]; //匹配
rep(j,,Len[i]) rep(k,L+,R) //不匹配
f[L][R][i][j]|=(f[L][k-][i][j]&cov[k][R]);
}
rep(i,,M) cov[L][R]|=f[L][R][i][Len[i]];
}
rep(i,,N){ //背包得到最大值
rep(j,,i) if(cov[j][i]) rep(k,i,N) dp[k]=max(dp[k],dp[j-]+i-j+);
rep(j,i+,N) dp[j]=max(dp[j],dp[j-]);
}
printf("%d\n",N-dp[N]);
return ;
}