hdu4117 GRE Words(ACAM+fail树+线段树)

首先我们有如果i< j,且 s i s j 的子串,那么有转移 f [ j ] = f [ i ] + w [ j ]
其中 f [ i ] 表示以第i个串结尾的最大答案。对 f [ i ] 取max即为答案。
我们考虑如何处理子串,把所有串先建出ACAM,然后拿每个串当文本串去跑,看有多少标号比我小且可以匹配上的。
这样是 O ( l e n 2 )
我们考虑优化,建出fail树,匹配到的每一个节点的所有祖先都是我的子串。我要找一个最大的,于是我们可以dfs序建出线段树,维护每个点到根的最大值。每次更新是子树取max。
复杂度 O ( l e n l o g   l e n )

这辣鸡题卡内存,怎么算也不够,不过可以动态的用一个清一个,这样实际使用的内存可以过qaq
如果你每次都大memset,那你就凉了qaq

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 20010
#define M 300010
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int n,son[M][26],fail[M],tid[N],ans,rt,owo=0,w[N],len[N],h[M],num;
int in[M],out[M],dfn;
char s[M];
struct node{
    int mx;
}tr[M<<2];
struct edge{
    int to,next;
}data[M];
inline void add(int x,int y){
    data[++num].to=y;data[num].next=h[x];h[x]=num;
}
inline int newp(){
    ++owo;memset(son[owo],0,sizeof(son[owo]));
    fail[owo]=0;h[owo]=0;return owo;
}
inline void ins(char *t,int id){
    int m=strlen(t+1),p=rt;
    for(int i=1;i<=m;++i){
        int &y=son[p][t[i]-'a'];if(!y) y=newp();p=y;
    }tid[id]=p;
}
inline void buildAC(){
    queue<int>q;q.push(rt);
    while(!q.empty()){
        int x=q.front();q.pop();
        for(int i=0;i<26;++i){
            int &y=son[x][i];
            if(!y){y=son[fail[x]][i];continue;}
            q.push(y);fail[y]=son[fail[x]][i];add(fail[y],y);
        }
    }
}
inline void dfs(int x){
    in[x]=++dfn;
    for(int i=h[x];i;i=data[i].next){
        int y=data[i].to;dfs(y);
    }out[x]=dfn;
}
inline void build(int p,int l,int r){
    tr[p].mx=0;if(l==r) return;int mid=l+r>>1;
    build(p<<1,l,mid);build(p<<1|1,mid+1,r);
}
inline void change(int p,int l,int r,int x,int y,int val){
    if(x<=l&&r<=y){tr[p].mx=max(tr[p].mx,val);return;}
    int mid=l+r>>1;
    if(x<=mid) change(p<<1,l,mid,x,y,val);
    if(y>mid) change(p<<1|1,mid+1,r,x,y,val);
}
inline int qmx(int p,int l,int r,int x){
    if(l==r) return tr[p].mx;int mid=l+r>>1;
    if(x<=mid) return max(qmx(p<<1,l,mid,x),tr[p].mx);
    return max(qmx(p<<1|1,mid+1,r,x),tr[p].mx);
}
inline int gao(char *t,int m,int id){
    int p=rt,res=0;
    for(int i=1;i<=m;++i){
        p=son[p][t[i]-'a'];
        res=max(res,qmx(1,1,owo,in[p]));
    }return res;
}
int main(){
//  freopen("a1.in","r",stdin);
    int tst=read();
    for(int i=0;i<26;++i) son[0][i]=1;
    for(int tt=1;tt<=tst;++tt){
        n=read();owo=0;ans=0;dfn=0;num=0;int now=1;rt=newp();
        for(int i=1;i<=n;++i){
            scanf("%s",s+now);w[i]=read();ins(s+now-1,i);
            len[i]=strlen(s+now);now+=len[i];
        }buildAC();dfs(rt);build(1,1,owo);now=1;
        change(1,1,owo,in[tid[1]],out[tid[1]],w[1]);ans=max(ans,w[1]);
        for(int i=2;i<=n;++i){
            now+=len[i-1];
            int res=gao(s+now-1,len[i],i);res+=w[i];ans=max(ans,res);
            change(1,1,owo,in[tid[i]],out[tid[i]],res);
        }printf("Case #%d: %d\n",tt,ans);
    }return 0;
}

猜你喜欢

转载自blog.csdn.net/icefox_zhx/article/details/80385884
gre