这题我的代码在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\n",++TT,mx); 173 } 174 }