zoj 3535 Gao the String II(AC自动机+DP)

来源:互联网 发布:淘宝售假申诉包成功 编辑:程序博客网 时间:2024/05/01 23:56

题意:给出两个字符串集合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;}




0 0
原创粉丝点击