[bzoj3277==bzoj3473]出现k次子串计数——广义后缀自动机+STL
Brief Description
给定n个字符串,对于每个字符串,您需要求出在所有字符串中出现次数大于等于k次的子串个数。
Algorithm Design
先建立一个广义后缀自动机,什么是广义后缀自动机?就是所有主串一起建立的一个后缀自动机。
广义后缀自动机的建立很简单,对于每个串,该怎么增量建立自动机就怎么建立,只不过为每个节点维护一个set保存这个节点的状态在那些字符串中出现过。当一个串增量构建完毕后,将后缀自动机的last指针指向后缀自动机的根即可进行下一发字符串的增量构建,这样就建出来了一发广义后缀自动机。
考虑一个节点,如果他在x个字符串中出现过,那么他的fa指针所指向的节点所代表的状态出现过的次数一定不小于他。
并且我们已经为每个节点维护了一个set来记录在那些字符串中出现过,那么我们只需要自下向上合并set集合即可,在这之前需要整理出parent树的具体形态,然后一遍dfs,逆序处理set的启发式合并即可。
统计答案只需把每个字符串在自动机上跑,跑到一个节点发现出现次数<K就往fa指针那里跳,直到符合条件。这时候贡献的答案就是当前节点的len属性的值了.
Code
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <set>
#include <string>
const int maxn = 200010;
using std::set;
using std::string;
#define ll long long
set<int> d[maxn];
set<int>::iterator it;
int n, K, tot = 1, head[maxn], sum[maxn];
struct edge {
int to, next;
} e[maxn * 6];
string str[maxn];
struct Suffix_Automaton {
int trans[maxn][26], len[maxn], sz;
int fa[maxn], last, root;
void init() {
tot = 0;
last = root = ++sz;
}
void add(int c, int id) {
int p = last, np = last = ++sz;
len[np] = len[p] + 1;
d[np].insert(id);
while (p && !trans[p][c])
trans[p][c] = np, p = fa[p];
if (!p)
fa[np] = root;
else {
int q = trans[p][c];
if (len[q] == len[p] + 1)
fa[np] = q;
else {
int nq = ++sz;
len[nq] = len[p] + 1;
fa[nq] = fa[q];
for (int i = 0; i < 26; i++)
trans[nq][i] = trans[q][i];
fa[q] = fa[np] = nq;
while (trans[p][c] == q)
trans[p][c] = nq, p = fa[p];
}
}
}
void print() {
for (int i = 1; i <= sz; i++) {
std::cout << fa[i] << ' ';
}
std::cout << std::endl;
for (int i = 1; i <= sz; i++)
printf("%d ", sum[i]);
printf("\n");
}
} sam;
void dfs(int x) {
for (int i = head[x]; i; i = e[i].next) {
int v = e[i].to;
dfs(v);
for (it = d[v].begin(); it != d[v].end(); it++)
d[x].insert(*it);
}
sum[x] = d[x].size();
}
void add_edge(int from, int to) {
e[++tot].to = to;
e[tot].next = head[from];
head[from] = tot;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("input", "r", stdin);
#endif
scanf("%d %d", &n, &K);
sam.init();
for (int i = 1; i <= n; i++) {
std::cin >> str[i];
int len = str[i].length();
for (int j = 0; j < len; j++)
sam.add(str[i][j] - 'a', i);
sam.last = sam.root;
}
for (int i = 1; i <= sam.sz; i++)
if (sam.fa[i])
add_edge(sam.fa[i], i);
dfs(sam.root);
// sam.print();
if (K > n) {
for (int i = 1; i <= n; i++)
printf("0 ");
return 0;
}
for (int i = 1; i <= n; i++) {
ll ans = 0;
int now = sam.root, len = str[i].length();
for (int j = 0; j < len; j++) {
now = sam.trans[now][str[i][j] - 'a'];
while (sum[now] < K)
now = sam.fa[now];
ans += sam.len[now];
}
printf("%lld ", ans);
}
return 0;
}
[bzoj3277==bzoj3473]出现k次子串计数——广义后缀自动机+STL的更多相关文章
- CodeForces-204E:Little Elephant and Strings (广义后缀自动机求出现次数)
The Little Elephant loves strings very much. He has an array a from n strings, consisting of lowerca ...
- 【bzoj3277/bzoj3473】串/字符串 广义后缀自动机
题目描述 字符串是oi界常考的问题.现在给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串(注意包括本身). 输入 第一行两个整数n,k.接下来n行每行一个 ...
- BZOJ3277 串 【广义后缀自动机】
Description 字符串是oi界常考的问题.现在给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中 至少k个字符串的子串(注意包括本身). Input 第一行两个整数n, ...
- BZOJ3277: 串(广义后缀自动机)
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1196 Solved: 478[Submit][Status][Discuss] Descripti ...
- BZOJ3473 字符串 【广义后缀自动机】
题目 给定n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串? 输入格式 第一行两个整数n,k. 接下来n行每行一个字符串. 输出格式 一行n个整数,第i个整数表 ...
- JDOJ 2939: Suffix Automaton 广义后缀自动机_统计子串
建立广义后缀自动机,对每个节点都建立各自的 $Parent$ 数组. 这样方便统计,不会出现统计错误. 考虑新加入一个字符. 1 这条转移边已经存在,显然对答案没有贡献. 2 这条转移边不存在,贡献即 ...
- 后缀自动机(SAM)+广义后缀自动机(GSA)
经过一顿操作之后竟然疑似没退役0 0 你是XCPC选手吗?我觉得我是! 稍微补一点之前丢给队友的知识吧,除了数论以外都可以看看,为Dhaka和新队伍做点准备... 不错的零基础教程见 IO WIKI ...
- bzoj3926: [Zjoi2015]诸神眷顾的幻想乡 对[广义后缀自动机]的一些理解
先说一下对后缀自动机的理解,主要是对构造过程的理解. 构造中,我们已经得到了前L个字符的后缀自动机,现在我们要得到L+1个字符的后缀自动机,什么需要改变呢? 首先,子串$[0,L+1)$对应的状态不存 ...
- BZOJ 3277 串 (广义后缀自动机)
3277: 串 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 309 Solved: 118 [Submit][Status][Discuss] De ...
随机推荐
- Android Google Maps 开始
由于工作需要,最近对Android的各大地图进行了试用. 其中有Google地图,百度地图,高德地图,还有开源的OSM. 在使用Google地图的时候,官网流程写的非常清楚,但是其中也遇到一些问题.这 ...
- python学习总结----异常处理
相关概念 - 错误:程序运行之前的语法错误,如:关键字.缩进不齐.括号不成对. - 异常:在程序运行过程中出现的问题,如:除数为0.对象属性不存在等. 异常处理 - 说明:异常处理可以理解为特殊的流程 ...
- Word2Vec词向量(一)
一.词向量基础(一)来源背景 word2vec是google在2013年推出的一个NLP工具,它的特点是将所有的词向量化,这样词与词之间就可以定量的去度量他们之间的关系,挖掘词之间的联系.虽然源码是 ...
- io学习2-磁盘阵列RAID
磁盘阵列 RAID(Redundant ArrayOf Inexpensive Disks) 如果你是一位数据库管理员或者经常接触服务器,那对RAID应该很熟悉了,作为最廉价的存储解决方案,RAID早 ...
- 关于php网络爬虫phpspider
前几天,被老板拉去说要我去抓取大众点评某家店的数据,当然被我义正言辞的拒绝了,理由是我不会...但我的反抗并没有什么卵用,所以还是乖乖去查资料,因为我是从事php工作的,首先找的就是php的网络爬虫源 ...
- 数组中键key相等时,后面的值覆盖前面的值
<?php $arr[]='abc'; $arr[]='; $arr[]='; $arr[]='; var_dump($arr); 结果;
- [OS] 进程相关知识点
进程概念: 1.程序在执行中 2.一个具有一定独立功能的程序在一个数据集合上的一次动态执行过程,是系统进行资源分配和调度的独立单位. 进程与程序的差别: ·进程----动态, 程序----静态 ·进程 ...
- hdu 1285 确定比赛名次 (拓扑)
确定比赛名次 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Subm ...
- JavaScript(二):对象、注释、事件!
对象 JavaScript的一个重要功能就是面向对象的功能,通过基于对象的程序设计,可以用更直观.模块化和可重复使用的方式进行程序开发. 一组包含数据的属性和对属性中包含数据进行操作的方法,称为对象. ...
- [Leetcode] rotate image 旋转图片
You are given an n x n 2D matrix representing an image. Rotate the image by 90 degrees (clockwise). ...