题意:给出两个字符串集合A,B,现在每次可以在集合A中挑一个字符串接在当前组成的串S后(可以重叠),对于每个长度不超过L的S串,S中每出现一个B中的串,那么这个串的价值加一,求串的最大的价值。
思路:把B插入Trie建立AC自动机。然后进行dp,dp[i][j][k]表示长度为i的串,最后接的一个串是j,此时状态为k时串的最大价值,然后对于每个状态,枚举一下能接下去的串就行了,注意接上去的串要至少让长度增加一,另外如果覆盖了上一个串,实际上这是没有意义的,所以不用考虑。本来以为复杂度会很高,但实际上没有那么糟糕。还有,给出的B的串有可能重复,这里要注意一下。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=555;
const int csize=26;
int ch[maxn][csize],lastv[maxn],flag[maxn];
int next[maxn],cnt[maxn],size;
char str[maxn],astr[55][15];
int m,n,L,dp[55][55][maxn],conect[55][55][15],lena[55];
void Init()
{
memset(ch[0],0,sizeof(ch[0]));
memset(cnt,0,sizeof(cnt));
memset(lastv,0,sizeof(lastv));
memset(flag,0,sizeof(flag));
memset(next,0,sizeof(next));
size=0;
}
void Insert(const char *s)
{
int u=0;
for(int i=0;s[i];++i)
{
int c=s[i]-'a';
if(!ch[u][c])
{
ch[u][c]=++size;
memset(ch[size],0,sizeof(ch[size]));
}
u=ch[u][c];
}
flag[u]++;
}
void build()
{
queue<int>q;
for(int i=0;i<csize;++i)
if(ch[0][i]) q.push(ch[0][i]);
int r,u;
while(!q.empty())
{
r=q.front();q.pop();
for(int c=0;c<csize;++c)
{
u=ch[r][c];
if(!u) {ch[r][c]=ch[next[r]][c];continue;}
q.push(u);
int j=next[r];
while(j&&!ch[j][c]) j=next[j];
next[u]=ch[j][c];
lastv[u]=flag[next[u]]?next[u]:lastv[next[u]];
}
}
for(int i=1;i<=size;++i)
{
u=i;
if(flag[u]||lastv[u])
{
u=flag[u]?u:lastv[u];
while(u)
{
cnt[i]+=flag[u];
u=lastv[u];
}
}
}
}
bool check(int x,int y,int z)
{
int lenx=lena[x];
if(z>lenx) return false;
for(int i=0;i<z;++i)
{
if(astr[x][lenx-z+i]!=astr[y][i]) return false;
}
return true;
}
int solve()
{
lena[0]=0;
memset(conect,0,sizeof(conect));
for(int i=1;i<=m;++i)
{
conect[0][i][0]=1,conect[0][i][1]=0;
lena[i]=strlen(astr[i]);
}
for(int i=1;i<=m;++i)
for(int j=1;j<=m;++j)
{
conect[i][j][0]=1;
conect[i][j][1]=0;
for(int k=1;k<lena[j];++k)
{
if(check(i,j,k)) {conect[i][j][0]++;conect[i][j][conect[i][j][0]]=k;}
}
}
memset(dp,0xff,sizeof(dp));
dp[0][0][0]=0;
int ans=0,u,c,tmp;
for(int i=0;i<=L;++i)
for(int j=0;j<=m;++j)
for(int k=0;k<=size;++k)
{
if(j==0&&i!=0) continue;
if(dp[i][j][k]==-1) continue;
if(dp[i][j][k]>ans) ans=dp[i][j][k];
for(int x=1;x<=m;++x)
for(int y=1;y<=conect[j][x][0];++y)
{
u=k;tmp=0;
for(int z=conect[j][x][y];astr[x][z];++z)
{
c=astr[x][z]-'a';
u=ch[u][c];
tmp+=cnt[u];
}
int pos=i+lena[x]-conect[j][x][y];
if(pos>L) continue;
if(dp[pos][x][u]==-1) dp[pos][x][u]=dp[i][j][k]+tmp;
else dp[pos][x][u]=max(dp[pos][x][u],dp[i][j][k]+tmp);
}
}
return ans;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
while(~scanf("%d%d%d",&m,&n,&L))
{
Init();
astr[0][0]='\0';
for(int i=1;i<=m;++i)
scanf("%s",astr[i]);
for(int i=0;i<n;++i)
{
scanf("%s",str);
Insert(str);
}
build();
int ans=solve();
printf("%d\n",ans);
}
return 0;
}