这题与KMP唯一的关系就是个判断。。。
首先,利用KMP算出哪些位置可以匹配。
然后显然有个DP[i][j]表示前i个字符,凑出的状态为j。为了处理相交情况,所以每次向后转移都必须枚举很多位置。然后可以利用树状数组优化,DP[i]=DP[j]+i-j这种形式的DP,可以先把DP[j]-j存下来,然后读取的时候直接读该位置的最大/最小值+i即可。
#include
#include
#include
#define SF scanf
#define PF printf
#define MAXN 10010
using namespace std;
char s[MAXN],s1[5][MAXN];
int len[5];
int fail[MAXN];
int m,n;
int tr1[20][MAXN],tr2[20][MAXN];
int sg[MAXN][20],sf[MAXN][20],f[MAXN][20],g[MAXN][20];
bool vis[MAXN];
int ch[MAXN];
void build(int x){
int i=0,j=-1;
fail[0]=-1;
while(i<len[x]){
if(j==-1||s1[x][i]==s1[x][j]){
i++;
j++;
fail[i]=j;
}
else
j=fail[j];
}
}
void solve(int x){
int i=0,j=0;
while(i<m){
if(j==-1||s[i]==s1[x][j]){
i++;
j++;
}
else
j=fail[j];
if(j==len[x])
ch[i-len[x]]|=(1<<(x-1));
}
}
int que1(int id,int i){
i++;
int res=tr1[id][0];
for(;i<=m+1;i+=i&(-i))
res=max(res,tr1[id][i]);
return res;
}
int que2(int id,int i){
i++;
int res=tr2[id][0];
for(;i<=m+1;i+=i&(-i))
res=min(res,tr2[id][i]);
return res;
}
void add1(int id,int i,int v){
i++;
for(;i;i-=i&(-i))
tr1[id][i]=max(tr1[id][i],v);
}
void add2(int id,int i,int v){
i++;
for(;i;i-=i&(-i))
tr2[id][i]=min(tr2[id][i],v);
}
int main(){
int t;
SF("%d",&t);
while(t--){
SF("%s",s);
m=strlen(s);
SF("%d",&n);
memset(ch,0,sizeof ch);
for(int i=1;i<=n;i++){
SF("%s",s1[i]);
len[i]=strlen(s1[i]);
memset(fail,0,sizeof fail);
build(i);
solve(i);
}
memset(vis,0,sizeof vis);
for(int a=1;a<=n;a++)
for(int b=1;b<=n;b++)
if(a!=b&&vis[a]==0&&vis[b]==0){
memset(fail,0,sizeof fail);
fail[0]=-1;
int j=-1;
int i=0;
while(i<len[a]){
if(j==-1||s1[a][i]==s1[a][j]){
i++;
j++;
fail[i]=j;
}
else
j=fail[j];
}
i=j=0;
while(i<len[b]){
if(j==-1||s1[b][i]==s1[a][j]){
i++;
j++;
}
else
j=fail[j];
if(j==len[a]){
vis[a]=1;
break;
}
}
}
int mask=(1<<n)-1;
for(int i=1;i<=n;i++)
if(vis[i]==1)
mask^=1<<(i-1);
memset(tr1,0xc0,sizeof tr1);
memset(tr2,0x3f,sizeof tr2);
memset(sf,0xc0,sizeof sf);
memset(sg,0x3f,sizeof sg);
memset(f,0xc0,sizeof f);
memset(g,0x3f,sizeof g);
for(int i=0;i<(1<<n);i++){
f[0][i]=0xc0;
g[0][i]=0x3f;
}
for(int i=0;i<=m;i++)
for(int j=0;j<(1<<n);j++){
if(i==0){
if(j==0)
f[0][0]=g[0][0]=sf[0][0]=sg[0][0]=0;
else{
f[0][j]=que1(j,i)+i;
g[0][j]=que2(j,i)+i;
}
}
else{
sf[i][j]=max(sf[i][j],sf[i-1][j]);
sg[i][j]=min(sg[i][j],sg[i-1][j]);
f[i][j]=max(sf[i][j],que1(j,i)+i);
g[i][j]=min(sg[i][j],que2(j,i)+i);
}
for(int k=1;k<=n;k++)
if((j&(1<<(k-1)))==0&&(ch[i]&(1<<(k-1)))){
int mask1=(j|(1<<(k-1)));
add1(mask1,i+len[k],f[i][j]-i);
sf[i+len[k]][mask1]=max(sf[i+len[k]][mask1],f[i][j]+len[k]);
if(vis[k]==0){
add2(mask1,i+len[k],g[i][j]-i);
sg[i+len[k]][mask1]=min(sg[i+len[k]][mask1],g[i][j]+len[k]);
}
}
}
int ans=0;
//PF("[%d]",mask);
for(int i=0;i<(1<<n);i++)
if((i&mask)==mask)
ans=max(ans,f[m][i]);
PF("%d %d\n",g[m][mask],ans);
}
}