第九周 10.25-10.31

10.25

HDU 4117 GRE Words

卡了很久的一个题目。比较综合。

看了很久题解还是各种写挫。

毕竟除了模拟题都没敲过那么长的。

题意:按顺序给N个单词,每个单词有权值,删去其中任意单词,使得前面的单词为后面单词的子串,求最大权值和。

做法:先建好AC自动机。

   最先想到的方法应该是这样的。

   定义dp[i]为以第i个串为最后一个串的答案。

   转移是dp[i]=max{W[i],dp[j]+W[i]}(j为i子串)

   那么只要再拿这N个单词在AC自动机上匹配一遍。

   每过一个节点相当于经过这个串的一个前缀。而这个节点的fail指向的是这个前缀的后缀。

   于是经过的每个节点时都通过fail一直走到root就遍历了这个串的所有子串。

   那么我们不妨定义f[u]为节点u所对应的单词的所有后缀的答案。

   那么可以用这种方法借助f[]来求出dp。

   

   然而这样是T的。

   于是考虑一种用线段树优化的方法。

   

   考虑到我们每次是顺着fail指针更新答案的。而且每次更新一个节点后只会影响fail指向它的节点。

   按照fail反向建树。这样每个父节点都是孩子节点的前缀。也就是每次更新一个节点后只影响它的子树。

   先在fail树上dfs一遍打好时间戳。

   线段树的每个节点维护时间戳所对应的fail树上节点的f[]值。

   于是按照段更新的区间最值线段树写就可以了。

   每次询问所有前缀的f[]。再更新末节点对应子树的f[]。

   所有取最大即为答案。

   

   最后防爆栈黑科技交C++。   

  1 #pragma comment(linker, "/STACK:102400000,102400000")
  2 #include <iostream>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <algorithm>
  6 #include <queue>
  7 using namespace std;
  8 const int maxnode=3e5+10,sigma_size=26;
  9 const int maxn=2e4+10;
 10 int n,p[maxn],W[maxn];
 11 char s[maxnode];
 12 
 13 //fail_tree
 14 int cnt,headlist[maxnode];
 15 int timer,dfn[maxnode][2];
 16 struct e
 17 {
 18     int to,pre;
 19 } edge[2*maxnode];
 20 
 21 void add(int from,int to)
 22 {
 23     cnt++;
 24     edge[cnt].pre=headlist[from];
 25     edge[cnt].to=to;
 26     headlist[from]=cnt;
 27 }
 28 
 29 void dfs(int pos,int fa)
 30 {
 31     dfn[pos][0]=++timer;
 32     for(int i=headlist[pos];i;i=edge[i].pre)
 33     {
 34         int to=edge[i].to;
 35         if(to==fa) continue;
 36         dfs(to,pos);
 37     }
 38     dfn[pos][1]=++timer;
 39 }
 40 
 41 //seg_tree
 42 struct seg_tree
 43 {
 44     int l,r,val;
 45 }tree[maxnode<<3];
 46 
 47 void buildtree(int pos,int l,int r)
 48 {
 49     tree[pos].l=l;
 50     tree[pos].r=r;
 51     tree[pos].val=0;
 52     if(l<r)
 53     {
 54         buildtree(pos*2,l,(l+r)/2);
 55         buildtree(pos*2+1,(l+r)/2+1,r);
 56     }
 57 }
 58 
 59 void pushdown(int pos)
 60 {
 61     tree[2*pos].val=max(tree[2*pos].val,tree[pos].val);
 62     tree[2*pos+1].val=max(tree[2*pos+1].val,tree[pos].val);
 63 }
 64 
 65 void update(int pos,int l,int r,int val)
 66 {
 67     if(tree[pos].l>=l&&tree[pos].r<=r) tree[pos].val=max(tree[pos].val,val);
 68     else
 69     {
 70         pushdown(pos);
 71         if((tree[pos].l+tree[pos].r)/2>=r) update(pos*2,l,r,val);
 72         else if((tree[pos].l+tree[pos].r)/2<l) update(pos*2+1,l,r,val);
 73         else
 74         {
 75             update(pos*2,l,r,val);
 76             update(pos*2+1,l,r,val);
 77         }
 78     }
 79 }
 80 
 81 int query(int pos,int l,int r)
 82 {
 83     if(tree[pos].l>=l&&tree[pos].r<=r) return tree[pos].val;
 84     int ret=0;
 85     pushdown(pos);
 86     if((tree[pos].l+tree[pos].r)/2>=r) ret=max(ret,query(pos*2,l,r));
 87     else if((tree[pos].l+tree[pos].r)/2<l) ret=max(ret,query(pos*2+1,l,r));
 88     else
 89     {
 90         ret=max(ret,query(pos*2,l,r));
 91         ret=max(ret,query(pos*2+1,l,r));
 92     }
 93     return ret;
 94 }
 95 
 96 struct Ac_auto
 97 {
 98     int Next[maxnode][sigma_size];
 99     int fail[maxnode];
100     int sz;
101     Ac_auto(){sz=1;memset(Next[0],0,sizeof(Next[0]));}
102     void init(){sz=1;memset(Next[0],0,sizeof(Next[0]));}
103     int idx(char c) {return c-'a';}
104 
105     void insert(char *s)
106     {
107         int u=0,n=strlen(s);
108         for(int i=0;i<n;i++)
109         {
110             int c=idx(s[i]);
111             if(!Next[u][c])
112             {
113                 memset(Next[sz],0,sizeof(Next[sz]));
114                 Next[u][c]=sz++;
115             }
116             u=Next[u][c];
117         }
118     }
119 
120     void build()
121     {
122         queue<int> q;
123         fail[0]=0;
124         for(int i=0;i<sigma_size;i++) if(Next[0][i])
125         {
126             fail[Next[0][i]]=0;
127             q.push(Next[0][i]);
128         }
129         while(!q.empty())
130         {
131             int pos=q.front(); q.pop();
132             for(int i=0;i<sigma_size;i++)
133             {
134                 if(!Next[pos][i]) Next[pos][i]=Next[fail[pos]][i];
135                 else
136                 {
137                     fail[Next[pos][i]]=Next[fail[pos]][i];
138                     q.push(Next[pos][i]);
139                 }
140             }
141         }
142     }
143 
144     void fail_tree()
145     {
146         cnt=0;
147         memset(headlist,0,sizeof(headlist));
148         for(int i=1;i<sz;i++)
149         {
150             add(i,fail[i]);
151             add(fail[i],i);
152         }
153     }
154 
155     int solve()
156     {
157         int ret=0;
158         for(int i=1;i<=n;i++)
159         {
160             int u=0,tmp=0;
161             for(int j=p[i-1];j<p[i];j++)
162             {
163                 u=Next[u][idx(s[j])];
164                 tmp=max(tmp,query(1,dfn[u][0],dfn[u][0])+W[i]);
165             }
166             ret=max(ret,tmp);
167             update(1,dfn[u][0],dfn[u][1],tmp);
168         }
169         return ret;
170     }
171 
172 }ACA;
173 
174 
175 int main(void)
176 {
177     int T; scanf("%d",&T);
178     for(int kase=1;kase<=T;kase++)
179     {
180         scanf("%d",&n);
181         ACA.init();
182         for(int i=1;i<=n;i++)
183         {
184             scanf("%s%d",s+p[i-1],W+i);
185             ACA.insert(s+p[i-1]);
186             p[i]=p[i-1]+strlen(s+p[i-1]);
187         }
188         ACA.build();
189         ACA.fail_tree();
190         timer=0;
191         dfs(0,-1);
192         buildtree(1,1,timer);
193         printf("Case #%d: %d
",kase,ACA.solve());
194     }
195     return 0;
196 }
Aguin

10.26-10.31

什么都没干。

原文地址:https://www.cnblogs.com/Aguin/p/4908313.html