博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
BZOJ3172: [Tjoi2013]单词
阅读量:5316 次
发布时间:2019-06-14

本文共 3172 字,大约阅读时间需要 10 分钟。

【传送门:】


简要题意:

  给出n个单词,你可以理解为将这些单词变成一个个段落,然后求出每个单词在所有段落中出现的次数


题解(一):

  刚开始不是很懂题目,结果发现将所有单词看成一篇文章,每个单词看成一个段落就懂了

  由于某种unbelievable的原因,我刚好做了AC自动机的专题训练,看到这道题就秒想AC自动机

  将每个单词放进AC自动机里,每个点的s表示有多少个单词经过,然后在构建失败指针的时候,通过队列来更新s值,怎么更新呢,假设有一个i点,它的失败指针指向j,设sj为从根到j点所构成的字符串,si为从根到i点所构成的字符串,那么我们可以知道sj为si的后缀,也说明了si中有sj的出现,那么就将j点的s值加上i点的s值,达到更新且不重复的目的来求出答案


 

参考代码(一):

#include
#include
#include
#include
#include
#include
using namespace std;struct node{ int s,c[27],fail; node() { s=fail=0; memset(c,-1,sizeof(c)); }}t[1100000];int tot,ans,n;char a[1100000];int ed[210];void bt(int k,int root){ int x=root,len=strlen(a+1); for(int i=1;i<=len;i++) { int y=a[i]-'a'+1; if(t[x].c[y]==-1) { t[x].c[y]=++tot; } x=t[x].c[y]; t[x].s++; } ed[k]=x;}int list[1100000];void bfs(){ int x; int head=1,tail=1; list[1]=0; while(head<=tail) { x=list[head]; for(int i=1;i<=26;i++) { int son=t[x].c[i]; if(son==-1)continue; if(x==0) t[son].fail=0; else { int j=t[x].fail; while(j!=0&&t[j].c[i]==-1) j=t[j].fail; t[son].fail=max(t[j].c[i],0); int x=t[son].fail,y=son; } list[++tail]=son; } head++; } for(int i=tail;i>=1;i--) t[t[list[i]].fail].s+=t[list[i]].s;}int main(){ ans=tot=0; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%s",a+1); bt(i,0); } bfs(); for(int i=1;i<=n;i++) { printf("%d\n",t[ed[i]].s); } return 0;}

 


 

题解(二):

    A了这道题之后才发现早在之前就A了(心酸)

  那我们就来搞一下第二种想法

  很容易就想到AC自动机,但是单单是AC自动机还不行

  这时就要用AC自动机的延伸——fail树来做(时常膜一膜算法,有益身体健康)

  fail树这个玩意就是将AC自动机中fail指针当成是一条边,然后建成一棵树

  由于trie树上的每个点相当于一个字符串,所以这棵fail树父亲节点是儿子节点所构成字符串的最长后缀

  这样子对于这道题而言,fail树简直就是神一般的存在QAQ

  首先将每个字符串放进trie树里面,并且每经过一个trie树里的点,就用s数组记录这个字符串出现的个数,每经过一次就加一,然后构造AC自动机,然后在构造AC自动机的过程中,对每个点的fail指针进行建边,然后用dfs从根往下遍历,把s数组从下往上累加

  然后在输入每个字符串的时候,记录每个字符串的最后一个字符在trie树上的编号,然后一个一个输出s[end[i]](end[i]表示第i个字符串最后一个字母在trie树上的编号)


参考代码(二):

#include
#include
#include
#include
#include
#include
using namespace std;struct node{ int c[27],fail; node() { fail=0; memset(c,-1,sizeof(c)); }}t[1100000];int tot,n;char st[1100000];int s[1100000];int end[1100000];void bt(int root,int z){ int x=root,len=strlen(st+1); for(int i=1;i<=len;i++) { int y=st[i]-'a'+1; if(t[x].c[y]==-1) { t[x].c[y]=++tot; } x=t[x].c[y];s[x]++; } end[z]=x;}struct edge{ int x,y,next;}a[1100000];int len,last[1100000];void ins(int x,int y){ len++; a[len].x=x;a[len].y=y; a[len].next=last[x];last[x]=len;}queue
q;void bfs(){ int x; q.push(0); while(q.empty()==0) { x=q.front(); for(int i=1;i<=26;i++) { int son=t[x].c[i]; if(son==-1)continue; if(x==0) t[son].fail=0; else { int j=t[x].fail; while(j!=0&&t[j].c[i]==-1) j=t[j].fail; t[son].fail=max(t[j].c[i],0); } ins(t[son].fail,son); q.push(son); } q.pop(); }}void dfs(int x){ for(int k=last[x];k;k=a[k].next) { int y=a[k].y; dfs(y); s[x]+=s[y]; }}int main(){ tot=0; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%s",st+1); bt(0,i); } len=0;memset(last,0,sizeof(last)); bfs(); dfs(0); for(int i=1;i<=n;i++) printf("%d\n",s[end[i]]); return 0;}

 

 

转载于:https://www.cnblogs.com/Never-mind/p/7628734.html

你可能感兴趣的文章
cocos2d-x 3.0rc2中读取sqlite文件
查看>>
Linux 2.6 完全公平调度算法CFS(Completely Fair Scheduler)分析
查看>>
海量数据处理面试题集锦
查看>>
【设计模式】命令模式
查看>>
pyinstaller---将py文件打包成exe
查看>>
readonly和const的区别
查看>>
VS 代码行数统计
查看>>
SSM框架搭建(四) springmvc和mybatis的配置
查看>>
UVa 11346 - Probability
查看>>
python数据类型之间的转换
查看>>
微软职位内部推荐-SDEII
查看>>
微软职位内部推荐-SENIOR SOFTWARE ENGINEER
查看>>
Redis系统性介绍
查看>>
(备忘)打开office2010总是在配置进度
查看>>
jquery中的ajax方法(备忘)
查看>>
iOS基础-高级视图-UITableView--静态单元格
查看>>
打印图片的属性和实现另存图片功能以及使用numpy
查看>>
IOS-网络(大文件下载)
查看>>
基于MySQL的高可用可扩展架构探讨
查看>>
linux系统服务设置命令--chkconfig命令参数及用法详解
查看>>