zoukankan      html  css  js  c++  java
  • BZOJ2905 : 背单词

    首先对所有单词建立AC自动机,$S$是$T$的子串等价于$T$的某个前缀通过$fail$链可以走到$S$的终止节点,即$S$的终止节点是$T$某个前缀在$fail$树上的祖先。

    设$f[i]$表示考虑了前$i$个单词,且第$i$个单词必选时子序列价值的最大值,

    则$f[i]=max(单词i每个前缀的贡献)+w[i]$,计算出$f[i]$后再在单词$i$终止节点在$fail$树的子树里打上$f[i]$的标记,线段树维护即可。

    时间复杂度$O(Llog L)$。

    #include<cstdio>
    #include<cstring>
    const int N=20010,M=300010;
    typedef long long ll;
    char s[M];
    int tot,son[M][26],fail[M],q[M],G[M],NXT[M],st[M],en[M],dfn;
    int Case,n,i,j,w[N],g[N],v[M],nxt[M],ed;
    ll tag[1050000],dp,ans;
    inline void ins(int p){
      for(int l=strlen(s),x=0,i=0,w;i<l;i++){
        if(!son[x][w=s[i]-'a'])son[x][w]=++tot;
        v[++ed]=x=son[x][w];nxt[ed]=g[p];g[p]=ed;
      }
    }
    void make(){
      int h=1,t=0,i,j,x;fail[0]=-1;
      for(i=0;i<26;i++)if(son[0][i])q[++t]=son[0][i];
      while(h<=t)for(x=q[h++],i=0;i<26;i++)
        if(son[x][i])fail[son[x][i]]=son[fail[x]][i],q[++t]=son[x][i];
        else son[x][i]=son[fail[x]][i];
    }
    void dfs(int x){
      st[x]=++dfn;
      for(int i=G[x];i;i=NXT[i])dfs(i);
      en[x]=dfn;
    }
    void build(int x,int a,int b){
      tag[x]=0;
      if(a==b)return;
      int mid=(a+b)>>1;
      build(x<<1,a,mid),build(x<<1|1,mid+1,b);
    }
    inline void up(ll&a,ll b){if(a<b)a=b;}
    void change(int x,int a,int b,int c,int d){
      if(c<=a&&b<=d){up(tag[x],dp);return;}
      int mid=(a+b)>>1;
      if(c<=mid)change(x<<1,a,mid,c,d);
      if(d>mid)change(x<<1|1,mid+1,b,c,d);
    }
    void ask(int x,int a,int b,int c){
      up(dp,tag[x]);
      if(a==b)return;
      int mid=(a+b)>>1;
      if(c<=mid)ask(x<<1,a,mid,c);else ask(x<<1|1,mid+1,b,c);
    }
    int main(){
      scanf("%d",&Case);
      while(Case--){
        scanf("%d",&n);
        for(i=1;i<=n;i++)scanf("%s%d",s,&w[i]),ins(i);
        make();
        for(i=1;i<=tot;i++)NXT[i]=G[fail[i]],G[fail[i]]=i;
        dfs(0);
        build(1,1,dfn);
        for(ans=0,i=1;i<=n;i++){
          for(dp=0,j=g[i];j;j=nxt[j])ask(1,1,dfn,st[v[j]]);
          up(ans,dp+=w[i]);
          change(1,1,dfn,st[v[g[i]]],en[v[g[i]]]);
        }
        printf("%lld
    ",ans);
        for(i=dfn=0;i<=tot;i++)for(fail[i]=G[i]=j=0;j<26;j++)son[i][j]=0;
        for(ed=tot=0,i=1;i<=n;i++)g[i]=0;
      }
      return 0;
    }
    

      

  • 相关阅读:
    poj 2312 Battle City
    poj 2002 Squares
    poj 3641 Pseudoprime numbers
    poj 3580 SuperMemo
    poj 3281 Dining
    poj 3259 Wormholes
    poj 3080 Blue Jeans
    poj 3070 Fibonacci
    poj 2887 Big String
    poj 2631 Roads in the North
  • 原文地址:https://www.cnblogs.com/clrs97/p/5125289.html
Copyright © 2011-2022 走看看