zoukankan      html  css  js  c++  java
  • 【uva1502/hdu4117-GRE Words】DP+线段树优化+AC自动机

    这题我的代码在hdu上AC,在uva上WA。

    题意:按顺序输入n个串以及它的权值di,要求在其中选取一些串,前一个必须是后一个的子串。问d值的和最大是多少。 (1≤n≤2×10^4 ,串的总长度<=3*10^5)

    题解:

    这题一开始我的方向就错了,想了很久d[x][y]表示在AC自动机上的节点x、下一个串要大于y的dp。然而这样做数组要10^4*10^5=10^9级别,开都开不了,妥妥超时。

    后来看了一眼题解。。。觉得自己智商真是感人。。。

    用f[i]表示以第i个串为结尾的时候最大的d值,这样做就可以知道在AC自动机上的位置、当前在第几个串。

    f[i]=max(f[j])+w[i],j所代表的串为i的子串。

    现在我们要快速知道子串:

    1.

    建立AC自动机,然后将fail反向建立fail树。

    对于fail树上某个点来说,它的祖先所代表的串必为它的子串(通过一直fail可以到达的点)

    fail树上做一遍dfs求出dfn,就可以做到线性时间维护子树的最值。

    2.

    字符串x在fail树上求到的子串是除了x本身、在其他字符串中求到的子串,但是x自己的某一段也是自己的子串。所以在AC自动机上走到x的末尾节点,所经过的路程每一个点所代表的字符串也是x的子串。

    对于每一个i,我把已求出来的f[i]放到failtree上它所对应的点,然后i的整个子树的最大值都要更新一遍。所以我们要开一棵线段树来维护,用failtree的dfn来作为线段树的下标,维护区间最大值。

    求f[i]的时候就在AC自动机上走一遍字符串i,对于每个经过的点询问一遍它的值-------解决了第二种子串

    询问i的末尾节点的值-----解决了第一种子串,因为在i前面、failtree上是i的祖先的点已经更新了i。

    然后取最值,放入failtree上,更新failtree的子树即可。

      1 //hdu4117
      2 
      3 #include<cstdio>
      4 #include<cstdlib>
      5 #include<cstring>
      6 #include<iostream>
      7 #include<queue>
      8 using namespace std;
      9 
     10 const int N=300010,M=20010,S=26;
     11 int n,num,cnt_dfn,cnt_seg,len,w[M],last[M],first[N],dfn[N],next_dfn[N];
     12 char s[N];
     13 struct trie_node{
     14     int fa,fail,son[30];
     15 }a[N];
     16 struct fail_node{
     17     int x,y,next;
     18 }b[N];
     19 struct seg_node{
     20     int lc,rc,l,r,d,lazy;
     21 }t[2*N];
     22 queue<int> q;
     23 
     24 int maxx(int x,int y){return x>y ? x:y;}
     25 
     26 void clear(int x)
     27 {
     28     a[x].fail=a[x].fa=0;
     29     memset(a[x].son,0,sizeof(a[x].son));
     30 }
     31 
     32 void ins(int x,int y)
     33 {
     34     b[++len].x=x;b[len].y=y;
     35     b[len].next=first[x];first[x]=len;
     36 }
     37 
     38 void read_trie(int id)
     39 {
     40     scanf("%s%d",s,&w[id]);
     41     int x=0,l=strlen(s);
     42     for(int i=0;i<l;i++)
     43     {
     44         // if(!(s[i]>='a' && s[i]<='z')) while(1) ;
     45         int ind=s[i]-'a'+1;
     46         if(!a[x].son[ind])
     47         {
     48             num++;
     49             clear(num);
     50             a[x].son[ind]=num;
     51             a[num].fa=x;
     52         }
     53         x=a[x].son[ind];
     54     }
     55     last[id]=x;
     56 }
     57 
     58 void build_AC_failtree()
     59 {
     60     while(!q.empty()) q.pop();
     61     for(int i=1;i<=S;i++) 
     62         if(a[0].son[i]) q.push(a[0].son[i]);
     63     while(!q.empty())
     64     {
     65         int x=q.front();q.pop();
     66         int fail=a[x].fail;
     67         for(int i=1;i<=S;i++)
     68         {
     69             if(a[x].son[i])
     70             {
     71                 a[a[x].son[i]].fail=a[fail].son[i];
     72                 q.push(a[x].son[i]);
     73             }
     74             else a[x].son[i]=a[fail].son[i];
     75         }
     76     }
     77     for(int i=1;i<=num;i++)
     78         ins(a[i].fail,i);
     79 }
     80 
     81 void make_dfn(int x)
     82 {
     83     dfn[x]=++cnt_dfn;
     84     for(int i=first[x];i;i=b[i].next) make_dfn(b[i].y);
     85     next_dfn[x]=cnt_dfn;
     86 }
     87 
     88 int build_segtree(int l,int r)
     89 {
     90     cnt_seg++;
     91     int x=cnt_seg;
     92     t[x].l=l;t[x].r=r;t[x].d=0;
     93     t[x].lc=t[x].rc=0;t[x].lazy=0;//debug 原本根节点是0,但是这里也是0,就WA了
     94     if(l!=r)
     95     {
     96         int mid=(l+r)>>1;
     97         t[x].lc=build_segtree(l,mid);
     98         t[x].rc=build_segtree(mid+1,r);
     99     }
    100     return x;
    101 }
    102 
    103 void updata(int x)
    104 {
    105     if(!t[x].lazy) return;
    106     int lazy=t[x].lazy,lc=t[x].lc,rc=t[x].rc;
    107     t[x].d=maxx(t[x].d,lazy);
    108     t[x].lazy=0;
    109     t[lc].lazy=maxx(t[lc].lazy,lazy);//debug****
    110     t[rc].lazy=maxx(t[rc].lazy,lazy);//debug****
    111 }
    112 
    113 void change(int x,int l,int r,int d)
    114 {
    115     updata(x);
    116     if(t[x].l==l && t[x].r==r) {t[x].lazy=d;return;}
    117     int lc=t[x].lc,rc=t[x].rc;
    118     int mid=(t[x].l+t[x].r)>>1;
    119     if(r<=mid) change(lc,l,r,d);
    120     else if(l>mid) change(rc,l,r,d);
    121     else 
    122     {
    123         change(lc,l,mid,d);
    124         change(rc,mid+1,r,d);
    125     }
    126     updata(lc);
    127     updata(rc);
    128     t[x].d=maxx(t[lc].d,t[rc].d);
    129 }
    130 
    131 int query(int x,int y)
    132 {
    133     if(t[x].lazy) updata(x);
    134     if(t[x].l==t[x].r) return t[x].d;
    135     int lc=t[x].lc,rc=t[x].rc;
    136     int mid=(t[x].l+t[x].r)>>1;
    137     if(y<=mid) return query(lc,y);
    138     if(y>mid) return query(rc,y);
    139 }
    140 
    141 int dp_AC(int x,int now,int id)
    142 {
    143     if(x==0) return now;
    144     return dp_AC(a[x].fa,maxx(now,query(1,dfn[x])),id);
    145 }
    146 
    147 int main()
    148 {
    149     //freopen("a.in","r",stdin);
    150     //freopen("a.out","w",stdout);
    151     int T,TT=0;
    152     scanf("%d",&T);
    153     while(T--)
    154     {
    155         scanf("%d",&n);
    156         num=0;len=0;cnt_dfn=-1;cnt_seg=0;//原本cnt_seg=-1,根节点=0,后来cnt_seg改成0,根节点=1
    157         clear(0);
    158         memset(first,0,sizeof(first));
    159         for(int i=1;i<=n;i++) read_trie(i);
    160         build_AC_failtree();
    161         make_dfn(0);
    162         build_segtree(1,num);
    163         //dp
    164         int mx=0,x,fx;
    165         for(int i=1;i<=n;i++)
    166         {
    167             x=last[i];
    168             fx=dp_AC(x,0,i)+w[i];
    169             change(1,dfn[x],next_dfn[x],fx);
    170             mx=maxx(mx,fx);
    171         }
    172         printf("Case #%d: %d
    ",++TT,mx);
    173     }
    174 }
  • 相关阅读:
    Tomcat启动报Error listenerStart错误
    The type javax.xml.rpc.ServiceException cannot be resolved.It is indirectly
    (转)Android之Adapter用法总结
    利用脚本启动java程序
    Android中的基类—抽取出来公共的方法
    关于 Android 中未公开的类(用@hide隐藏的类)
    Android java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
    gen already exists but is not a source folder
    如何注册java程序为windows服务
    Android Socket编程
  • 原文地址:https://www.cnblogs.com/KonjakJuruo/p/5680063.html
Copyright © 2011-2022 走看看