A. Censoring
题目描述
FJ把杂志上所有的文章摘抄了下来并把它变成了一个长度不超过10^5??的字符串S。他有一个包含n个单词的列表,列表里的n个单词记为t1~t?N。他希望从S中删除这些单词。
FJ每次在S中找到最早出现的列表中的单词(最早出现指该单词的开始位置最小),然后从S中删除这个单词。他重复这个操作直到S中没有列表里的单词为止。注意删除一个单词后可能会导致S中出现另一个列表中的单词
FJ注意到列表中的单词不会出现一个单词是另一个单词子串的情况,这意味着每个列表中的单词在S中出现的开始位置是互不相同的
请帮助FJ完成这些操作并输出最后的S
输入格式
第一行包含一个字符串S
第二行包含一个整数N N<2000 接下来的N行,每行包含一个字符串,第i行的字符串是ti
输出格式
一行,输出操作后的S
样例
样例输入
begintheescapexecutionatthebreakofdawn
2
escape
execution
样例输出
beginthatthebreakofdawn
基本上是板子,但是AC自动机会TLE1个点,这个题最后一个点会一直跳。。。
所以要用Trie图。
考试代码(WA 40)
#include<iostream> #include<cstring> #include<string> #include<cstdio> #include<queue> #define Reg register using namespace std; int n,front,stack[100050],len[2050]; char s[100050],ls[100050]; struct Tree {Tree *next[26],*fail;int rank;}; Tree *New() { Tree *p=new Tree; for(Reg int i=0;i<26;++i) p->next[i]=NULL; p->fail=NULL; p->rank=0; return p; } Tree *root=New(); Tree *pos[100050]; void Insert(char s[],int k) { int l=strlen(s); len[k]=l; Tree *p=root; for(Reg int i=0,x;i<l;++i) { x=s[i]-‘a‘; if(p->next[x]==NULL) p->next[x]=New(); p=p->next[x]; } p->rank=k; return; } void GetFail() { queue<Tree *> q; q.push(root); while(!q.empty()) { Tree *p=q.front(); q.pop(); for(Reg int i=0;i<26;++i) { if(p->next[i]==NULL) continue; if(p==root) p->next[i]->fail=root; else { Tree *tmp=p->fail; while(tmp!=NULL) { if(tmp->next[i]!=NULL) { p->next[i]->fail=tmp->next[i]; break; } tmp=tmp->fail; } if(tmp==NULL) p->next[i]->fail=root; } q.push(p->next[i]); } } return; } void GetAc(char s[]) { int l=strlen(s); Tree *p=root; for(Reg int i=0;i<l;++i) { stack[++front]=s[i]-‘a‘; int x=stack[front]; while(p!=NULL&&p->next[x]==NULL) p=p->fail; if(p==NULL) p=root; else { p=p->next[x]; if(p->rank>0) { front-=len[p->rank]; p=pos[i-len[p->rank]]; } } pos[i]=p; } for(Reg int i=1;i<=front;++i) printf("%c",(char)stack[i]+‘a‘); return; } int main() { scanf("%s",s); scanf("%d",&n); for(Reg int i=1;i<=n;++i) { scanf("%s",ls); Insert(ls,i); } GetFail(); GetAc(s); return 0; }
改正AC自动机代码(TLE 93)
#include<iostream> #include<cstring> #include<string> #include<cstdio> #include<queue> #define Reg register using namespace std; int n,front,stack[1000050],len[1000050]; char s[1000050],ls[1000050]; struct Tree {Tree *next[26],*fail;int rank;}; Tree *New() { Tree *p=new Tree; for(Reg int i=0;i<26;++i) p->next[i]=NULL; p->fail=NULL; p->rank=0; return p; } Tree *root=New(); Tree *pos[1000050]; void Insert(char s[],int k) { int l=strlen(s); len[k]=l; Tree *p=root; for(Reg int i=0;i<l;++i) { int x=s[i]-‘a‘; if(p->next[x]==NULL) p->next[x]=New(); p=p->next[x]; } p->rank=k; return; } void GetFail() { queue<Tree *> q; q.push(root); root->fail=NULL; while(!q.empty()) { Tree *p=q.front(); q.pop(); for(Reg int i=0;i<26;++i) { if(p->next[i]==NULL) continue; if(p==root) p->next[i]->fail=root; else { Tree *tmp=p->fail; while(tmp!=NULL) { if(tmp->next[i]!=NULL) { p->next[i]->fail=tmp->next[i]; break; } tmp=tmp->fail; } if(tmp==NULL) p->next[i]->fail=root; } q.push(p->next[i]); } } return; } void GetAc(char s[]) { int l=strlen(s); Tree *p=root; pos[0]=root; for(Reg int i=0;i<l;++i) { stack[++front]=s[i]-‘a‘; int x=stack[front]; while(p->next[x]==NULL&&p!=root) p=p->fail; p=p->next[x]; if(p==NULL) p=root; pos[front]=p; if(p->rank>0) { front-=len[p->rank]; p=pos[front]; } } for(Reg int i=1;i<=front;++i) printf("%c",(char)stack[i]+‘a‘); return; } int main() { scanf("%s",s); scanf("%d",&n); for(Reg int i=1;i<=n;++i) { scanf("%s",ls); Insert(ls,i); } GetFail(); GetAc(s); return 0; }
正解Trie图代码(AC)
#include<iostream> #include<cstring> #include<string> #include<cstdio> #include<queue> #define Reg register using namespace std; int n,front,stack[100050],len[100050]; char s[100050],ls[100050]; struct Tree {Tree *next[26],*fail;int rank;}; Tree *New() { Tree *p=new Tree; for(Reg int i=0;i<26;++i) p->next[i]=NULL; p->fail=NULL; p->rank=0; return p; } Tree *root=New(); Tree *pos[100050]; void Insert(char s[],int k) { int l=strlen(s); len[k]=l; Tree *p=root; for(Reg int i=0;i<l;++i) { int x=s[i]-‘a‘; if(p->next[x]==NULL) p->next[x]=New(); p=p->next[x]; } p->rank=k; return; } void GetFail() { queue<Tree *> q; q.push(root); while(!q.empty()) { Tree *p=q.front(); q.pop(); for(Reg int i=0;i<26;++i) { if(p->next[i]!=NULL) { if(p==root) p->next[i]->fail=p; else p->next[i]->fail=p->fail->next[i]; q.push(p->next[i]); } else { if(p==root) p->next[i]=p; else p->next[i]=p->fail->next[i]; } } } return; } void GetAc(char s[]) { int l=strlen(s); Tree *p=root; pos[0]=root; for(Reg int i=0;i<l;++i) { stack[++front]=s[i]-‘a‘; int x=stack[front]; p=p->next[x]; pos[front]=p; if(p->rank>0) { front-=len[p->rank]; p=pos[front]; } } for(Reg int i=1;i<=front;++i) printf("%c",(char)stack[i]+‘a‘); return; } int main() { scanf("%s",s); scanf("%d",&n); for(Reg int i=1;i<=n;++i) { scanf("%s",ls); Insert(ls,i); } GetFail(); GetAc(s); return 0; }
其实改动不大,就是Trie图没有看过。
B. 记忆的轮廓
题目描述
通往贤者之塔的路上,有许多的危机。
我们可以把这个地形看做是一颗树,根节点编号为1,目标节点编号为n,其中1-n的简单路径上,编号依次递增,在[1,n]中,一共有n个节点。我们把编号在[1,n]的叫做正确节点,[n+1,m]的叫做错误节点。一个叶子,如果是正确节点则为正确叶子,否则称为错误叶子。莎缇拉要帮助昴到达贤者之塔,因此现在面临着存档位置设定的问题。
为了让昴成长为英雄,因此一共只有p次存档的机会,其中1和n必须存档。被莎缇拉设置为要存档的节点称为存档位置。当然不能让昴陷入死循环,所以存档只能在正确节点上进行,而且同一个节点不能存多次档。因为通往贤者之塔的路上有影响的瘴气,因此莎缇拉假设昴每次位于树上一个节点时,都会等概率选择一个儿子走下去。每当走到一个错误叶子时,再走一步就会读档。具体的,每次昴到达一个新的存档位置,存档点便会更新为这个位置(假如现在的存档点是i,现在走到了一个存档位置j>i,那么存档点便会更新为j)。读档的意思就是回到当前存档点。初始昴位于1,当昴走到正确节点n时,便结束了路程。莎缇拉想知道,最优情况下,昴结束路程的期望步数是多少?
输入格式
第一行一个正整数T表示数据组数。
接下来每组数据,首先读入三个正整数n,m,p。
接下来m-n行,描述树上所有的非正确边(正确边即连接两个正确节点的边)
用两个正整数j,k表示j与k之间有一条连边,j和k可以均为错误节点,也可以一个为正确节点另一个为错误节点。
数据保证j是k的父亲。
50<=p<=n<=700,m<=1500,T<=5。
数据保证每个正确节点均有至少2个儿子,至多3个儿子。
输出格式
T行每行一个实数表示每组数据的答案。请保留四位小数。
样例
样例输入
1
3 7 2
1 4
2 5
3 6
3 7
样例输出
9.0000
这应该是个我做不出来的题好题。。。
C. 雨天的尾巴
题目描述
N个点,形成一个树状结构。有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品。完成所有发放后,每个点存放最多的是哪种物品。
输入格式
第一行数字N,M
接下来N-1行,每行两个数字a,b,表示a与b间有一条边
再接下来M行,每行三个数字x,y,z.如题
输出格式
输出有N行
每i行的数字表示第i个点存放最多的物品是哪一种,如果有
多种物品的数量一样,输出编号最小的。如果某个点没有物品则输出0
样例
样例输入
20 50
8 6
10 6
18 6
20 10
7 20
2 18
19 8
1 6
14 20
16 10
13 19
3 14
17 18
11 19
4 11
15 14
5 18
9 10
12 15
11 14 87
12 1 87
14 3 84
17 2 36
6 5 93
17 6 87
10 14 93
5 16 78
6 15 93
15 5 16
11 8 50
17 19 50
5 4 87
15 20 78
1 17 50
20 13 87
7 15 22
16 11 94
19 8 87
18 3 93
13 13 87
2 1 87
2 6 22
5 20 84
10 12 93
18 12 87
16 10 93
8 17 93
14 7 36
7 4 22
5 9 87
13 10 16
20 11 50
9 16 84
10 17 16
19 6 87
12 2 36
20 9 94
9 2 84
14 1 94
5 5 94
8 17 16
12 8 36
20 17 78
12 18 50
16 8 94
2 19 36
10 18 36
14 19 50
4 12 50
样例输出
87
36
84
22
87
87
22
50
84
87
50
36
87
93
36
94
16
87
50
50
数据范围与提示
1<=N,M<=100000
1<=a,b,x,y<=N
1<=z<=10^9
考试代码(WA 0)
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #define Reg register using namespace std; int n,m,tot,sum,size,fir[100050],las[100050],vis[100050],fat[100050][25],ins[100050]; int que1[100050],que2[100050],que3[100050],lss[100050],ans[100050]; struct Tu {int st,ed,val,next;} lian[200050]; struct Tree {int lch,rch,date;} tree[8000050]; void add(int x,int y) { lian[++tot].st=x; lian[tot].ed=y; lian[tot].next=las[x]; las[x]=tot; return; } void dfs(int x) { vis[x]=1; for(Reg int j=1;j<=20;++j) fat[x][j]=fat[fat[x][j-1]][j-1]; for(Reg int i=las[x];i;i=lian[i].next) { if(!vis[lian[i].ed]) { fat[lian[i].ed][0]=x; ins[lian[i].ed]=ins[x]+1; dfs(lian[i].ed); } } return; } int lca(int x,int y) { if(ins[x]<ins[y]) swap(x,y); if(ins[x]!=ins[y]) { for(Reg int i=20;i>=0;--i) if(ins[fat[x][i]]>ins[y]) x=fat[x][i]; if(x==y) return x; x=fat[x][0]; if(x==y) return x; } if(x==y) return x; for(Reg int i=20;i>=0;--i) { if(fat[x][i]!=fat[y][i]) { x=fat[x][i]; y=fat[y][i]; } } return fat[x][0]; } int add_num(int k,int l,int r,int pos,int val) { if(!k) k=++size; if(l==r) { tree[k].date+=val; return k; } int mid=(l+r)/2; if(pos<=mid) tree[k].lch=add_num(tree[k].lch,l,mid,pos,val); else tree[k].rch=add_num(tree[k].rch,mid+1,r,pos,val); tree[k].date=max(tree[tree[k].lch].date,tree[tree[k].rch].date); return k; } void work(int l,int r,int num) { int f=lca(l,r); fir[l]=add_num(fir[l],1,sum,num,1); fir[r]=add_num(fir[r],1,sum,num,1); fir[f]=add_num(fir[f],1,sum,num,-1); if(fat[f][0]) fir[fat[f][0]]=add_num(fir[fat[f][0]],1,sum,num,-1); return; } int merge(int x,int y,int l,int r) { tree[0].date=-0x7fffffff; if(!x||!y) return x+y; if(l==r) { tree[x].date+=tree[y].date; return x; } int mid=(l+r)/2; if(l<=mid) tree[x].lch=merge(tree[x].lch,tree[y].lch,l,mid); if(mid+1<=r) tree[x].rch=merge(tree[x].rch,tree[y].rch,mid+1,r); tree[x].date=max(tree[tree[x].lch].date,tree[tree[x].rch].date); // cout<<l<<‘ ‘<<r<<" "<<tree[x].lch<<‘ ‘<<tree[x].rch<<" "<<tree[tree[x].lch].date<<‘ ‘<<tree[tree[x].rch].date<<" "<<tree[x].date<<endl; return x; } int ask(int x,int l,int r) { if(l==r) return l; int mid=(l+r)/2; if(tree[tree[x].lch].date<=0&&tree[tree[x].rch].date<=0) return 0; if(tree[x].lch&&tree[tree[x].lch].date>tree[tree[x].rch].date) return ask(tree[x].lch,l,mid); else if(tree[x].lch&&tree[tree[x].lch].date==tree[tree[x].rch].date) return ask(tree[x].lch,l,mid); else if(tree[x].rch&&tree[tree[x].lch].date<tree[tree[x].rch].date) return ask(tree[x].rch,mid+1,r); else return 0; } int aaa(int x,int l,int r,int num) { if(!x) return 0; if(l==r) return tree[x].date; int mid=(l+r)/2; if(num<=mid) return aaa(tree[x].lch,l,mid,num); else return aaa(tree[x].rch,mid+1,r,num); } void dfs_re(int x) { vis[x]=1; for(Reg int i=las[x];i;i=lian[i].next) { if(!vis[lian[i].ed]) { dfs_re(lian[i].ed); fir[x]=merge(fir[x],fir[lian[i].ed],1,sum); } } ans[x]=ask(fir[x],1,sum); // cout<<x<<" "; // for(Reg int i=1;i<=sum;++i) // { // printf("%d ",aaa(fir[x],1,sum,i)); // } // cout<<endl; return; } int main() { scanf("%d%d",&n,&m); tree[0].date=-0x7fffffff; for(Reg int i=1,x,y;i<=n-1;++i) { scanf("%d%d",&x,&y); add(x,y); add(y,x); } ins[1]=1; dfs(1); for(Reg int i=1,x,y,z;i<=m;++i) { scanf("%d%d%d",&que1[i],&que2[i],&que3[i]); lss[i]=que3[i]; } sort(lss+1,lss+m+1,less<int>()); sum=unique(lss+1,lss+m+1)-lss-1; for(Reg int i=1;i<=m;++i) que3[i]=lower_bound(lss+1,lss+m+1,que3[i])-lss; for(Reg int i=1;i<=m;++i) work(que1[i],que2[i],que3[i]); memset(vis,0,sizeof(vis)); dfs_re(1); for(Reg int i=1;i<=n;++i) printf("%d\n",lss[ans[i]]); return 0; }
AC代码(AC)
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #define Reg register using namespace std; int n,m,tot,sum,size,fir[100050],las[100050],vis[100050],fat[100050][25],ins[100050]; int que1[100050],que2[100050],que3[100050],lss[100050],ans[100050]; struct Tu {int st,ed,val,next;} lian[200050]; struct Tree {int lch,rch,date;} tree[8000050]; void add(int x,int y) { lian[++tot].st=x; lian[tot].ed=y; lian[tot].next=las[x]; las[x]=tot; return; } void dfs(int x) { vis[x]=1; for(Reg int j=1;j<=20;++j) fat[x][j]=fat[fat[x][j-1]][j-1]; for(Reg int i=las[x];i;i=lian[i].next) { if(!vis[lian[i].ed]) { fat[lian[i].ed][0]=x; ins[lian[i].ed]=ins[x]+1; dfs(lian[i].ed); } } return; } int lca(int x,int y) { if(ins[x]<ins[y]) swap(x,y); if(ins[x]!=ins[y]) { for(Reg int i=20;i>=0;--i) if(ins[fat[x][i]]>ins[y]) x=fat[x][i]; if(x==y) return x; x=fat[x][0]; if(x==y) return x; } if(x==y) return x; for(Reg int i=20;i>=0;--i) { if(fat[x][i]!=fat[y][i]) { x=fat[x][i]; y=fat[y][i]; } } return fat[x][0]; } int add_num(int k,int l,int r,int pos,int val) { if(!k) k=++size; if(l==r) { tree[k].date+=val; return k; } int mid=(l+r)/2; if(pos<=mid) tree[k].lch=add_num(tree[k].lch,l,mid,pos,val); else tree[k].rch=add_num(tree[k].rch,mid+1,r,pos,val); tree[k].date=max(tree[tree[k].lch].date,tree[tree[k].rch].date); return k; } void work(int l,int r,int num) { int f=lca(l,r); fir[l]=add_num(fir[l],1,sum,num,1); fir[r]=add_num(fir[r],1,sum,num,1); fir[f]=add_num(fir[f],1,sum,num,-1); if(fat[f][0]) fir[fat[f][0]]=add_num(fir[fat[f][0]],1,sum,num,-1); return; } int merge(int x,int y,int l,int r) { tree[0].date=-0x7fffffff; if(!x||!y) return x+y; if(l==r) { tree[x].date+=tree[y].date; return x; } int mid=(l+r)/2; if(l<=mid) tree[x].lch=merge(tree[x].lch,tree[y].lch,l,mid); if(mid+1<=r) tree[x].rch=merge(tree[x].rch,tree[y].rch,mid+1,r); tree[x].date=max(tree[tree[x].lch].date,tree[tree[x].rch].date); // cout<<l<<‘ ‘<<r<<" "<<tree[x].lch<<‘ ‘<<tree[x].rch<<" "<<tree[tree[x].lch].date<<‘ ‘<<tree[tree[x].rch].date<<" "<<tree[x].date<<endl; return x; } int ask(int x,int l,int r) { if(l==r) return l; int mid=(l+r)/2; if(tree[tree[x].lch].date<=0&&tree[tree[x].rch].date<=0) return 0; if(tree[x].lch&&tree[tree[x].lch].date>tree[tree[x].rch].date) return ask(tree[x].lch,l,mid); else if(tree[x].lch&&tree[tree[x].lch].date==tree[tree[x].rch].date) return ask(tree[x].lch,l,mid); else if(tree[x].rch&&tree[tree[x].lch].date<tree[tree[x].rch].date) return ask(tree[x].rch,mid+1,r); else return 0; } int aaa(int x,int l,int r,int num) { if(!x) return 0; if(l==r) return tree[x].date; int mid=(l+r)/2; if(num<=mid) return aaa(tree[x].lch,l,mid,num); else return aaa(tree[x].rch,mid+1,r,num); } void dfs_re(int x) { vis[x]=1; for(Reg int i=las[x];i;i=lian[i].next) { if(!vis[lian[i].ed]) { dfs_re(lian[i].ed); fir[x]=merge(fir[x],fir[lian[i].ed],1,sum); } } ans[x]=ask(fir[x],1,sum); return; } int main() { scanf("%d%d",&n,&m); tree[0].date=-0x7fffffff; for(Reg int i=1,x,y;i<=n-1;++i) { scanf("%d%d",&x,&y); add(x,y); add(y,x); } ins[1]=1; dfs(1); for(Reg int i=1,x,y,z;i<=m;++i) { scanf("%d%d%d",&que1[i],&que2[i],&que3[i]); lss[i]=que3[i]; } sort(lss+1,lss+m+1,less<int>()); sum=unique(lss+1,lss+m+1)-lss-1; for(Reg int i=1;i<=m;++i) que3[i]=lower_bound(lss+1,lss+sum+1,que3[i])-lss; for(Reg int i=1;i<=m;++i) work(que1[i],que2[i],que3[i]); memset(vis,0,sizeof(vis)); dfs_re(1); for(Reg int i=1;i<=n;++i) printf("%d\n",lss[ans[i]]); return 0; }
这个题就尴尬了,离散化时的unique函数里写错了一个变量,导致改了这个题一个下午。。
原文地址:https://www.cnblogs.com/Milk-Feng/p/11025372.html