题目描述

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

输入

第一行两个整数n,k。
接下来n行每行一个字符串。

输出

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

样例输入

3 1
abc
a
ab

样例输出

6 1 3


题解

广义后缀自动机

建立广义后缀自动机,统计一下每个节点属于多少个字符串中。

在每次插入新节点np后,parent树上np的父亲节点fa[np]一定有着np的身份,即一定包含当前串(这里将root节点视作在所有串中)。

那么沿着parent树一直向上更新即可。更新到已经被更新过的节点就停止。

这样时间复杂度是O(n)的。

求出每个节点在几个子串中以后,还要知道出现次数。

而出现次数有一个定理:x结尾的不重复字符串的出现次数=dis[x]-dis[fa[x]]。

简单证明一下:从root走到parent树上x到root的链上的点共有dis[x]种方法,走到fa[x]到root的链上的点共有dis[fa[x]]种方法,相减可推出结论。

而仅仅求出不重复字符串的出现次数还不够,我们需要统计所有的出现位置。而出现位置一定是在parent树中从x到叶子结点均出现的。

那么可以用类似于树形dp的方法求解。

总结一下:建立广义后缀自动机,同时统计每个节点在多少个字符串中出现过。保留出现在≥k个字符串中的,令出现次数为dis[x]-dis[fa[x]]。然后树形dp,c[x]+=c[fa[x]],并更新答案求解。

说了这么多,其实代码也就几十行~

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 200010
using namespace std;
int a[N][26] , fa[N] , kind[N] , type[N] , si[N] , last , tot = 1;
int head[N] , to[N] , next[N] , cnt;
long long dis[N] , c[N] , ans[N];
char str[N];
void add(int x , int y)
{
to[++cnt] = y , next[cnt] = head[x] , head[x] = cnt;
}
void ins(int t , int c)
{
int p = last , np = last = ++tot;
dis[np] = dis[p] + 1 , kind[np] = t;
while(p && !a[p][c]) a[p][c] = np , p = fa[p];
if(!p) fa[np] = 1;
else
{
int q = a[p][c];
if(dis[q] == dis[p] + 1) fa[np] = q;
else
{
int nq = ++tot;
memcpy(a[nq] , a[q] , sizeof(a[q])) , dis[nq] = dis[p] + 1 , fa[nq] = fa[q] , fa[np] = fa[q] = nq , si[nq] = si[q] , type[nq] = type[q];
while(p && a[p][c] == q) a[p][c] = nq , p = fa[p];
}
}
for(p = np ; p && type[p] != t ; p = fa[p]) si[p] ++ , type[p] = t;
}
void dfs(int x)
{
int i;
c[x] += c[fa[x]] , ans[kind[x]] += c[x];
for(i = head[x] ; i ; i = next[i])
dfs(to[i]);
}
int main()
{
int n , m , k , i , j;
scanf("%d%d" , &n , &k);
for(i = 1 ; i <= n ; i ++ )
{
scanf("%s" , str + 1) , m = strlen(str + 1) , last = 1;
for(j = 1 ; j <= m ; j ++ ) ins(i , str[j] - 'a');
}
for(i = 2 ; i <= tot ; i ++ )
{
add(fa[i] , i);
if(si[i] >= k) c[i] = dis[i] - dis[fa[i]];
}
dfs(1);
for(i = 1 ; i <= n ; i ++ ) printf("%lld " , ans[i]);
return 0;
}

【bzoj3277/bzoj3473】串/字符串 广义后缀自动机的更多相关文章

  1. 【BZOJ3227】串【广义后缀自动机】

    题意 给出n个字符串,问每个字符串中有多少子串是这所有的n个字符串中至少k个的子串. 分析 广义后缀自动机模板题.对这n个串建广义后缀自动机,对于每个状态维护两个值cou[u]和lcu[u]分别代表拥 ...

  2. BZOJ3277 串 【广义后缀自动机】

    Description 字符串是oi界常考的问题.现在给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中 至少k个字符串的子串(注意包括本身). Input 第一行两个整数n, ...

  3. BZOJ 3473: 字符串 [广义后缀自动机]

    3473: 字符串 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 354  Solved: 160[Submit][Status][Discuss] ...

  4. BZOJ 3277 串 & BZOJ 3473 字符串 (广义后缀自动机、时间复杂度分析、启发式合并、线段树合并、主席树)

    标签那么长是因为做法太多了... 题目链接: (bzoj 3277) https://www.lydsy.com/JudgeOnline/problem.php?id=3277 (bzoj 3473) ...

  5. BZOJ3473 字符串 广义后缀自动机

    今天主攻了下SAM 好多东西以前都没理解到 对于这道题 我们建一个自动机存所有串 每个穿last从1开始 对于自动机上每个点额外记一个cnt 表示能匹配到这个点的不同串个数 建完对每个串在自动机上匹配 ...

  6. BZOJ 3473 字符串 ——广义后缀自动机

    这题就比较有趣了. 首先匹配一遍,然后统计子树叶子节点中包含大于等于k的节点个数(HH的项链) 然后就可以搞了. 关于合法的情况数,显然是l[i]-l[fa[i]],然后向下下传即可(YY一下). # ...

  7. [bzoj2780][Spoj8093]Sevenk Love Oimaster_广义后缀自动机

    Sevenk Love Oimaster bzoj-2780 Spoj-8093 题目大意:给定$n$个大串和$m$次询问,每次给出一个字符串$s$询问在多少个大串中出现过. 注释:$1\le n\l ...

  8. JZOJ5915 [2018NOIP模拟] 明日之星(广义后缀自动机,线段树)

    题目描述 给定一棵树,每个节点有一个权值 \(a_i\) 和一个字符串 \(s_i\). q组询问,每次询问一个字符串 S 和两个节点x,y: 求x到y路径上每个节点的字符串在 S 中出现的次数乘上各 ...

  9. CF 666E Forensic Examination——广义后缀自动机+线段树合并

    题目:http://codeforces.com/contest/666/problem/E 对模式串建广义后缀自动机,询问的时候把询问子串对应到广义后缀自动机的节点上,就处理了“区间”询问. 还要处 ...

随机推荐

  1. 2017.12.11 String 类中常用的方法

    1.编写程序将 "jdk" 全部变为大写,并输出到屏幕,截取子串"DK" 并输出到屏幕 package demo; import java.util.Scann ...

  2. python_18_三元运算

    # result=值1 if 条件 else 值2 如果条件为真:result=值1,否则result=值2. a,b,c=1,3,5 d=a if b>c else c print(d)

  3. 1.VS Code 开发C#入门 安装Dotnet core

    1. dot.net  网站 下载 .NET Core 1.0  (https://www.microsoft.com/net/download/core) 2. 打开命名提示符: 3.dotnet ...

  4. Python F-string 更快的格式化

    Python的格式化有%s,format,F-string,下面是比较这三种格式化的速度比较 In [12]: a = 'hello' In [13]: b = 'world' In [14]: f' ...

  5. cuda api查询问题

    在查询CUDA运行时API的时候,我用360极速浏览器的时候搜索结果一直不出来,但是用火狐的话就很流畅,所以建议大家在开发时还是用火狐浏览器.

  6. 阿里云服务器下安装LAMP环境(CentOS Linux 6.3) 安装与配置 php

    下面我们一起为服务器安装 PHP,在使用 yum 安装软件包的时候,yum 会去默认的资源库里查看我们要安装的软件包,然后到指定的服务器上下载并安装. 但是有的时候,我们要安装的软件包并没有包含在默认 ...

  7. Java面向对象之继承,方法重写,super关键字,员工类系列继承题

    在程序中,如果想声明一个类继承另一个类,需要使用extends关键字. 格式: class 子类 extends 父类 {} 继承的好处 1.继承的出现提高了代码的复用性,提高软件开发效率. 2.继承 ...

  8. vue学习之路 - 2.基本操作(上)

    基本操作(上) 本章节简介: vue的安装 vue实例创建 数据绑定渲染 表单数据双向绑定 事件处理 安装 安装方式有三种: 一.vue官网直接下载 http://vuejs.org/js/vue.m ...

  9. 火狐IE event和target的兼容

    一.event对象 IE 中可以直接使用 window.event 对象,而 FF 中则不可以,解决方法之一如下: var theEvent = window.event || arguments.c ...

  10. python之质数

    质数(prime number)又称素数,有无限个 质数定义为在大于1的自然数中,除了1和它本身以外不再有其他因数. 示例: num=[]; i=2 for i in range(2,100): j= ...