[BZOJ3277]串 广义后缀自动机

3277: 串

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 811  Solved: 329
[Submit][Status][Discuss]

Description

字符串是oi界常考的问题。现在给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中

至少k个字符串的子串(注意包括本身)。

Input

第一行两个整数n,k。

接下来n行每行一个字符串。

n,k,l<=100000

Output

输出一行n个整数,第i个整数表示第i个字符串的答案。

Sample Input

3 1

abc

a

ab

Sample Output

6 1 3

HINT

Source

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<cstdio>
 7 #define maxn 200005
 8 using namespace std;
 9 int n,k;
10 long long c[maxn];
11 long long ans[maxn];
12 struct data {
13     long long son[maxn][26],link[maxn],step[maxn],last,cnt,t[maxn],size[maxn],tp[maxn];
14     data() {last=cnt=1;}
15     void extend(int x,int id) {
16         int p=last,np=last=++cnt;step[np]=step[p]+1;t[np]=id;
17         while(p&&!son[p][x]) son[p][x]=np,p=link[p];
18         if(!p) link[np]=1;
19         else {
20             int q=son[p][x];
21             if(step[q]==step[p]+1) link[np]=q;
22             else {
23                 int nq=++cnt;
24                 memcpy(son[nq],son[q],sizeof(son[q]));
25                 step[nq]=step[p]+1;
26                 link[nq]=link[q];link[np]=link[q]=nq;size[nq]=size[q];tp[nq]=tp[q];
27                 while(p&&son[p][x]==q) son[p][x]=nq,p=link[p];
28             }
29         }
30         for(int i=np;i&&tp[i]!=id;i=link[i]) size[i]++,tp[i]=id;
31     }
32 }sam;
33 int head[maxn],sum;
34 struct edge {
35     int to,next;
36 }e[maxn];
37 void add(int u,int v) {e[sum].to=v;e[sum].next=head[u];head[u]=sum++;}
38 char s[maxn];
39 void dfs(int x) {
40     c[x]+=c[sam.link[x]];ans[sam.t[x]]+=c[x];
41     for(int i=head[x];i>=0;i=e[i].next) dfs(e[i].to);
42 }
43 int main() {
44     memset(head,-1,sizeof(head));
45     scanf("%d%d",&n,&k);
46     for(int i=1;i<=n;i++) {
47         scanf("%s",s+1);
48         int len=strlen(s+1);sam.last=1;
49         for(int j=1;j<=len;j++) sam.extend(s[j]-‘a‘,i);
50     }
51     for(int i=2;i<=sam.cnt;i++)    {
52         add(sam.link[i],i);
53         if(sam.size[i]>=k) c[i]=sam.step[i]-sam.step[sam.link[i]];
54     }
55     dfs(1);
56     for(int i=1;i<=n;i++) printf("%lld ",ans[i]);
57 }
58 /*
59 3 2
60 abaac
61 bba
62 bbacb
63 */

原文地址:https://www.cnblogs.com/wls001/p/8474695.html

时间: 2024-10-11 08:33:42

[BZOJ3277]串 广义后缀自动机的相关文章

BZOJ 3277 串 (广义后缀自动机)

3277: 串 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 309 Solved: 118 [Submit][Status][Discuss] Description 字符串是oi界常考的问题.现在给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串(注意包括本身). Input 第一行两个整数n,k. 接下来n行每行一个字符串. Output 输出一行n个整数,第i个整数表示第i个字符串的答案. Sa

【BZOJ3926】[Zjoi2015]诸神眷顾的幻想乡 广义后缀自动机

[BZOJ3926][Zjoi2015]诸神眷顾的幻想乡 Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看.幽香当然也非常高兴啦. 这时幽香发现了一件非常有趣的事情,太阳花田有n块空地.在过去,幽香为了方便,在这n块空地之间修建了n-1条边将它们连通起来.也就是说,这n块空地形成了一个树的结构. 有n个粉丝们来到了太阳花田上.为了表达对幽香生日的祝

E. Three strings 广义后缀自动机

http://codeforces.com/problemset/problem/452/E 多个主串的模型. 建立一个广义后缀自动机,可以dp出每个状态的endpos集合大小.同时也维护一个R[]表示那个串出现过. 所以可以算出每个状态的dp[i][k]表示第k个串在第i个状态中出现的次数. 可以知道sigma dp[i][0...k]是等于  endpos集合的大小. 然后把这个贡献加到min(i)....max(i)中去就可以了 差分一下. #include <bits/stdc++.h>

广义后缀自动机

1).自动机的介绍 首先我们先来介绍一下什么是自动机,有限状态自动机的功能是识别字符串,令一个自动机A,若他能识别字符串S,就记为A(S)=Ture,否则A(S)=False. 自动机由五个部分组成,alpha:字符集,state:状态集合,init:初始状态,end:结束状态集合,trans:状态转移函数. 令trans(s,ch)表示当前状态是s,在读入字符ch之后,所到达的状态.如果trans(s,ch)这个转移不存在,为了方便,设其为null,同时null只能转移到null.null表示

hdu 5853 Jong Hyok and String(广义后缀自动机)

题目链接:hdu 5853 Jong Hyok and String 题意: 给你n个字符串,m个询问,每次询问一个字符串 定义set(s)={(i,j)} 表示 s在第i个字符串中出现,且末尾位置为j. 对于一个询问,求set(Qi)=set(t) ,t串的数量. 题解: 如果是n=1,那么就是后缀自动机的一道裸题,答案就是Qi串匹配的最后一个节点x,ml[x]-ml[f[x]]. 现在是多个串,那么就建立一个广义后缀自动机.每次插入一个串后,将last=root,然后继续插下一个就行了. 最

【codeforces666E】Forensic Examination 广义后缀自动机+树上倍增+线段树合并

题目描述 给出 $S$ 串和 $m$ 个 $T_i$ 串,$q$ 次询问,每次询问给出 $l$ .$r$ .$x$ .$y$ ,求 $S_{x...y}$ 在 $T_l,T_{l+1},...,T_r$ 中的哪一个里出现次数最多,输出出现次数最多的串编号(如果有多个则输出编号最小的)以及相应出现次数. $|S|,q\le 5\times 10^5$ ,$\sum\limits_{i=1}^m|T_i|\le 5\times 10^4$ . 题解 广义后缀自动机+树上倍增+线段树合并 对 $S$

广义后缀自动机模板

后缀自动机能解决很多单串的问题.但是一旦到了多串的情况.可能就会变得有些棘手 这个时候你可能会想能不能将多个串一起构建出和单串后缀自动机那样子拥有诸多优美性质的自动机呢? 答案当然是有的.那就是广义后缀自动机 对于广义后缀自动机.和普通的后缀自动机写法上有些许不同之处 大致就是在插入新串的时候.需要把当前状态指针 last 指回 root 还有一个问题.网上的人们都说广义后缀自动机在新插入节点的时候要判是否已经存在 这个就造成了代码的迥异 关于代码.借鉴了这个博客 ==> Click here

bzoj 4566 找相同字符 —— 广义后缀自动机

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4566 建出两个串的广义后缀自动机: 统计每个点在两个串中出现次数的子树和,其实就是在两个串中的 right 集合大小: 然后统计答案乘起来即可. 代码如下: #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; int co

【BZOJ2806】【CTSC2012】Cheat 广义后缀自动机+二分+Dp

题目 题目在这里 思路&做法 我们先对标准作文库建广义后缀自动机. 然后对于每一篇阿米巴的作文, 我们首先把放到广义后缀自动机跑一遍, 对于每一个位置, 记录公共子串的长度\((\)即代码和下文中的\(val\)数组\()\) 接着我们二分答案, 用DP检验. Dp方程很好想, \(d_i = max \{ d_j + i - j \ | \ i-val_i <= j <= i-lim \}\) 可以用单点队列优化. 代码 #include <iostream> #incl