第九周 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\n",kase,ACA.solve()); 194 } 195 return 0; 196 }
10.26-10.31
什么都没干。