博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Codeforces 235C
阅读量:4883 次
发布时间:2019-06-11

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

 题目大意:

给定一个字符串,接下来再给n个字符串,求原字符串中含有多少个当前给定字符串的循环同构体的字符串的个数

 

以初始字符串构建后缀自动机,在自动机上前进的时候,比如当前需要匹配的字符串为aba,到达某个状态点S

我们所希望知道的所有aba出现的次数,因为aba最终到达的是点S,其实可以理解为整个后缀自动机通过f(父指针)形成了一棵后缀树

而这个S是后缀树上的叶子节点,那么上方所有的父亲节点都包含这个S,我们只需要找到最顶端的能达到aba状态的根节点,在根状态上记录其下方出现此后缀总共出现的个数

那么首先将后缀自动机拓扑排序,然后节点逆向访问,不断更新父亲节点的信息,用节点上的cnt变量记录当前节点作为根节点时所能得到的后缀的总个数

 

对于每个当前每个给定的字符串,因为要求循环同构,那么再连接一个相同的字符串在其后方,然后正常在后缀自动机上跑,当匹配到的长度大于len时,说明这个字符串中包含了循环同构体,我们就要不断逆向通过父亲回溯到根节点,这个根节点表示所能达到的长度尽可能小却仍旧大于等于len即可,因为这样的点是当前匹配所有作为大于len的后缀的节点的祖先。然后通过当前节点的flag标记判断当前节点是否被访问过来获取其中的cnt

1 #include 
2 #include
3 #include
4 using namespace std; 5 6 #define N 1000010 7 #define ll long long 8 struct SamNode{ 9 SamNode *son[26] , *f;10 int l , cnt , flag;11 void init(){12 for(int i=0 ; i<26 ; i++) son[i] = NULL;13 f=NULL;14 l = flag = cnt = 0;15 }16 }sam[N<<1] , *root , *last , *b[N<<1];17 18 int cnt , n , num[N];19 char s[N] , str[N];20 21 void add(int x)22 {23 SamNode *p = &sam[++cnt] , *jp = last;24 p->l = jp->l+1 ;25 last = p;26 for( ; jp&&!jp->son[x] ; jp=jp->f) jp->son[x] = p;27 if(!jp) p->f = root;28 else{29 if(jp->l+1 == jp->son[x]->l) p->f = jp->son[x];30 else{31 SamNode *r = &sam[++cnt] , *q = jp->son[x];32 *r = *q;33 r->l = jp->l+1;34 p->f = q->f = r;35 for( ; jp&&jp->son[x]==q ; jp=jp->f) jp->son[x]=r;36 }37 }38 }39 40 void solve()41 {42 scanf("%d" , &n);43 for(int mark=1 ; mark<=n ; mark++){44 scanf("%s" , str);45 int len = strlen(str) , ret = 0 ;46 ll ans = 0;47 SamNode *cur = root;48 for(int i=0 ; i<2*len ; i++){49 int x = (i>=len?str[i-len]:str[i])-'a';50 if(cur->son[x]){51 cur = cur->son[x];52 ret++;53 }54 else{55 while(cur && !cur->son[x]) cur = cur->f;56 if(!cur) cur=root , ret=0;57 else{58 ret = cur->l+1;59 cur=cur->son[x];60 }61 }62 while(cur->f&&cur->f->l>=len){63 cur = cur->f;64 ret = cur->l;65 }66 if(ret>=len && cur->flag!=mark) cur->flag=mark , ans= ans+cur->cnt;67 }68 printf("%I64d\n" , ans);69 }70 }71 72 int main()73 {74 // freopen("a.in" , "r", stdin);75 scanf("%s" , s);76 int len = strlen(s);77 sam[0].init();78 root = last = &sam[cnt=0];79 for(int i=0 ; i
son[s[i]-'a'];86 cur->cnt++;87 }88 for(int i=cnt ; i>0 ; i--) b[i]->f->cnt+=b[i]->cnt , b[i]->flag=0;89 solve();90 return 0;91 }

 

转载于:https://www.cnblogs.com/CSU3901130321/p/4598460.html

你可能感兴趣的文章
IbatisNet配置文件
查看>>
git形成本地仓库并从远处url拉取
查看>>
获取xml字符串中的属性值
查看>>
MySQL必知必会(数据分组,Group by和Having子句, Select子句的顺序)
查看>>
通过wireshark抓包来讲解HTTP中Connection: keep-alive头部的作用
查看>>
2015长春 HDU 5531 Rebuild
查看>>
Android之四种加载方式
查看>>
团队项目3.0
查看>>
【js】操作checkbox radio 的操作总结
查看>>
mysql复制表(同一数据库,不同数据库)
查看>>
Spring中 @Autowired标签与 @Resource标签
查看>>
面向对象的六大原则
查看>>
python的基本用法(三)字符串常用函数
查看>>
第二章例2-2
查看>>
Java8——快速入门手册(学习笔记)
查看>>
p2p-如何拯救k8s镜像分发的阿喀琉斯之踵
查看>>
linux之多进程
查看>>
iphone设置铃声
查看>>
python基础
查看>>
HDU 3277 最大流+二分
查看>>