HDU6138

来源:互联网 发布:流星网络电视看不了 编辑:程序博客网 时间:2024/06/01 09:57

先构造AC自动机,完了以后对于x,y,先用x把x的所有子串标记了,再用y去寻找是否y的子串为也是x的子串,根据字典树的性质,这已经保证了一定是原先某字串的前缀了。一开始T掉我还以为数据卡的恨死,结果是小细节错误,while(v && !ch[v][c])写成了while(!ch[v][c])导致死循环,xushu教了几个细节,不用吧所有串压到一个char数组里后面再调取,直接记录每个串的末尾节点,然后从后往前遍历,而且对于每次操作不要清空val数组,只需贴上时间戳,判断即可,而且每次只要找到被标记的立刻break,能保证是最长的,也保证每次查询每个点只走一次。然而优化先后竟然都是31ms?应该是HDU评测机问题。

#include<cstdio>#include<cstring>#define maxl 100010int n,m,sz,ans;int a[maxl],bgn[maxl],val[maxl],fail[maxl],dis[maxl];int endind[maxl],from[maxl];int ch[maxl][26];char s[maxl];int max(int x,int y){if(x>y)return x;elsereturn y;}void insert(char *s,int x){int c,len=strlen(s),u=0;for(int i=0;i<len;i++){c=s[i]-'a';if(!ch[u][c]){sz++;dis[sz]=dis[u]+1;from[sz]=u;ch[u][c]=sz;}u=ch[u][c];}endind[x]=u;}void prework(){int len;sz=0;ans=0;memset(ch,0,sizeof(ch));memset(val,0,sizeof(val));memset(fail,0,sizeof(fail));memset(dis,0,sizeof(dis));scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%s",s);insert(s,i);}}void getfail(){int u=0,v,head=0,tail=0,cur;for(int c=0;c<26;c++)if(ch[0][c])a[++tail]=ch[0][c];while(head!=tail){head=(head+1)%maxl;cur=a[head];for(int c=0;c<26;c++)if(ch[cur][c]){u=ch[cur][c];/*if(!u){ch[cur][c]=ch[fail[cur]][c];continue;}*/tail=(tail+1)%maxl;a[tail]=u;v=fail[cur];while(v && !ch[v][c]) v=fail[v];fail[u]=ch[v][c];}}}void getin(int x,int i){int u=endind[x],c,j;while(u){j=u;while(j){val[j]=i;j=fail[j];if(val[j]==i)break;}u=from[u];}}void getout(int y,int i){int u=endind[y],c,j;while(u){j=u;while(j && dis[j]>ans){if(val[j]==i){ans=max(dis[j],ans);break;}j=fail[j];}u=from[u];}}void mainwork(){getfail();int x,y;scanf("%d",&m);for(int i=1;i<=m;i++){scanf("%d%d",&x,&y);getin(x,i);ans=0;getout(y,i);printf("%d\n",ans);}}int main(){int cas;scanf("%d",&cas);for(int i=1;i<=cas;i++){prework();mainwork();}return 0;}


原创粉丝点击