题意:
给出A集合有m个穿,B集合有n个串,现在要求A集合中的串进行组合成长度不超过L的串S,是的包含最多B集合的串。
题解:
这题真心orz。dp[i][j][k]表示长度为i,在ac自动机上的状态j,并且是以k为结尾的A中的串。
预处理出每个A集合中的串和其他A集合中的串拼接的长度,因为任何两个串拼接的长度可以有多个,所以暴力枚举拼接的长度然后判断是否可行。注意:空串可以拼接任何串在开始位置!
接着就是丧心病狂的dp,无法直视那个循环的层数。
#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define B(x) (1<<(x))
typedef long long ll;
//typedef unsigned __int64 Ull;
const int oo=0x3f3f3f3f;
//const ll OO=1LL<<61;
const int MOD=10007;
const int maxn=15;
const int SIZE=505;
const int type=26;
char str[55][maxn];
int dp[SIZE][SIZE][55];
int len[55];
vector<int> pos[55],mat[55];///匹配在b串中的位置
struct ACautomaton
{
int next[SIZE][type],fail[SIZE],word[SIZE];
int cnt,root;
int newNode()
{
for(int i=0;i<type;i++)
next[cnt][i]=-1;
word[cnt++]=0;
return cnt-1;
}
void Init()
{
cnt=0;
root=newNode();
}
void Insert(char buff[])
{
int now=root;
for(int i=0,k;buff[i];i++)
{
k=buff[i]-'a';
if(next[now][k]==-1)
next[now][k]=newNode();
now=next[now][k];
}
word[now]++;
}
void build()
{
fail[root]=root;
int now=root;
queue<int>Q;
for(int i=0;i<type;i++)
{
if(next[now][i]==-1)
next[now][i]=root;
else
{
fail[next[now][i]]=root;
Q.push(next[now][i]);
}
}
while(!Q.empty())
{
now=Q.front();
Q.pop();
word[now]+=word[fail[now]];
for(int i=0;i<type;i++)
{
if(next[now][i]==-1)
next[now][i]=next[fail[now]][i];
else
{
fail[next[now][i]]=next[fail[now]][i];
Q.push(next[now][i]);
}
}
}
}
int cmax(int& a,int b)
{
if(b>a) a=b;
}
void PreSolve(int m)
{
for(int i=1;i<=m;i++)
{
mat[i].clear();
pos[i].clear();
for(int j=1;j<=m;j++)
{
for(int k=0;k<=len[j]&&k<=len[i];k++)
{
int f=1;
for(int s=1;s<=k;s++)
{
if(str[i][len[i]-k+s]!=str[j][s])
{
f=0;
break;
}
}
if(f)
{
mat[i].push_back(j);
pos[i].push_back(k+1);
}
}
}
}
///空串可以从开始位置拼接任何串
mat[0].clear();
pos[0].clear();
for(int i=1;i<=m;i++)
{
mat[0].push_back(i);
pos[0].push_back(1);
}
}
int DP(int m,int n,int L)
{
PreSolve(m);
int temp,sum,nt,start,l;
memset(dp,-1,sizeof dp);
dp[0][0][0]=0;
int ans=0;
for(int i=0;i<L;i++)
{
for(int j=0;j<cnt;j++)
{
for(int k=0;k<=m;k++)
if(dp[i][j][k]!=-1)
{
for(int t=0;t<mat[k].size();t++)
{
nt=mat[k][t];
start=pos[k][t];
temp=j;
sum=0;
l=len[nt]-start+1;
if(i+l>L)continue;
for(int s=start;s<=len[nt];s++)
{
temp=next[temp][str[nt][s]-'a'];
sum+=word[temp];
}
cmax(dp[i+l][temp][nt],dp[i][j][k]+sum);
cmax(ans,dp[i+l][temp][nt]);
}
}
}
}
return ans;
}
}ac;
int main()
{
int n,m,L;
char tc[15];
while(scanf("%d %d %d",&m,&n,&L)!=EOF)
{
ac.Init();
for(int i=1;i<=m;i++)
{
scanf("%s",str[i]+1);
len[i]=strlen(str[i]+1);
}
for(int i=1;i<=n;i++)
{
scanf("%s",tc);
ac.Insert(tc);
}
ac.build();
cout<<ac.DP(m,n,L)<<endl;
}
return 0;
}
/**
3
01
11
00000
3
011
11
00000
*/