BZOJ3277 串 【广义后缀自动机】
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
思路
假设不管k的限制,答案应该就是在后缀自动机上面跑到每个点在parent树上到根路径上贡献的和
每个点的贡献就是\(p->maxl-p->prt->maxl\)
然后这个维护直接\(o(n)\)递推就可以了
然后维护每个子串在哪些子串中出现过也很简单
虽然很暴力
直接建出广义后缀自动机之后再把每个串在后缀自动机上跑一遍
跑到的每个节点只需要更新它所有的prt节点就可以了
为了避免算重记录下当前节点上一次是被哪个标记访问的就可以了
#include<bits/stdc++.h>
using namespace std;
#define N 100010
#define fu(a,b,c) for(int a=b;a<=c;++a)
const int CHARSET_SIZE=26;
int n,k;
struct Sam{
Sam *ch[CHARSET_SIZE],*prt;
int maxl,val,pre;
Sam(int maxl=0):maxl(maxl){}
};
struct Suffix_Automaton{
Sam pool[N<<1],*cur,*root;
int buc[N];vector<Sam*> topo;
Suffix_Automaton(){cur=pool;root=new (cur++)Sam;}
Sam *extend(int c,Sam *last){
Sam *u=new (cur++)Sam(last->maxl+1),*v=last;
for(;v&&!v->ch[c];v=v->prt)v->ch[c]=u;
if(!v)u->prt=root;
else if(v->ch[c]->maxl==v->maxl+1){
u->prt=v->ch[c];
}else{
Sam *n=new (cur++)Sam(v->maxl+1),*o=v->ch[c];
copy(o->ch,o->ch+CHARSET_SIZE,n->ch);
n->prt=o->prt;
o->prt=u->prt=n;
for(;v&&v->ch[c]==o;v=v->prt)v->ch[c]=n;
}
return u;
}
void init(){
for(Sam *p=pool+1;p!=cur;p++){
if((signed)p->val<k)p->val=0;
else p->val=p->maxl-p->prt->maxl;
}
int maxv=0;
for(Sam *p=pool;p!=cur;p++){
maxv=max(maxv,p->maxl);
buc[p->maxl]++;
}
fu(i,1,maxv)buc[i]+=buc[i-1];
topo.resize(cur-pool);
for(Sam *p=pool;p!=cur;p++)topo[--buc[p->maxl]]=p;
fu(p,1,(signed)topo.size()-1)
topo[p]->val+=topo[p]->prt->val;
}
}sam;
struct Node{
Node *ch[CHARSET_SIZE];
};
struct Trie{
Node pool[N],*cur,*root;
Trie(){cur=pool;root=new (cur++)Node;}
Node *insert(Node *last,int c){
if(!last->ch[c])last->ch[c]=new (cur++)Node;
return last->ch[c];
}
void insert(char *s,int id){
int len=strlen(s);
Node *last=root;
fu(i,0,len-1)last=insert(last,s[i]-'a');
}
#define pi pair<Node*,Sam*>
void bfs(){
queue<pi> q;
q.push(pi(root,sam.root));
while(!q.empty()){
pi u=q.front();q.pop();
fu(i,0,25)if(u.first->ch[i]){
Sam *tmp=sam.extend(i,u.second);
q.push(pi(u.first->ch[i],tmp));
}
}
}
}trie;
char s[N];
int bg[N],en[N],c[N];
int main(){
freopen("input.txt","r",stdin);
scanf("%d%d",&n,&k);
int tot=0;
fu(i,1,n){
scanf("%s",s);
int len=strlen(s);
trie.insert(s,i);
bg[i]=tot+1;
fu(j,0,len-1)c[++tot]=s[j]-'a';
en[i]=tot;
}
trie.bfs();
fu(i,1,n){
Sam *now=sam.root;
fu(j,bg[i],en[i]){
now=now->ch[c[j]];
Sam *tmp=now;
for(;tmp!=sam.root&&tmp->pre!=i;tmp=tmp->prt)
tmp->pre=i,tmp->val++;
}
}
sam.init();
fu(i,1,n){
int ans=0;
Sam *now=sam.root;
fu(j,bg[i],en[i]){
for(;now&&!now->ch[c[j]];now=now->prt);
if(now){
now=now->ch[c[j]];
ans+=now->val;
}else now=sam.root;
}
printf("%d ",ans);
}
return 0;
}
BZOJ3277 串 【广义后缀自动机】的更多相关文章
- BZOJ3277: 串(广义后缀自动机)
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1196 Solved: 478[Submit][Status][Discuss] Descripti ...
- BZOJ 3277 串 (广义后缀自动机)
3277: 串 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 309 Solved: 118 [Submit][Status][Discuss] De ...
- BZOJ3277: 串(后缀自动机,Parent树,Dfs序)
Description 字符串是oi界常考的问题.现在给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中 至少k个字符串的子串(注意包括本身). Input 第一行两个整数n, ...
- BZOJ3277 串(后缀自动机)
对多串建立SAM的一种方法是加分隔符.于是加完分隔符建出SAM. 考虑统计出每个节点被多少个串包含.让每个串各自在SAM上跑,跑到一个节点就标记(显然一定会完全匹配该节点,因为是对包含其的串建的SAM ...
- 2018.12.22 bzoj3277: 串(后缀自动机+启发式合并)
传送门 跟这道题是一模一样的. 于是本蒟蒻又写了一遍10min1A庆祝 代码: #include<bits/stdc++.h> #define ri register int using ...
- 【bzoj3277/bzoj3473】串/字符串 广义后缀自动机
题目描述 字符串是oi界常考的问题.现在给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串(注意包括本身). 输入 第一行两个整数n,k.接下来n行每行一个 ...
- 【BZOJ3277】串(后缀自动机)
[BZOJ3277]串(后缀自动机) 题面 BZOJ 题解 广义后缀自动机??? 照着别人的打了一遍.. 相当于每个串都构建一个后缀自动机 构建完一个串之后,直接把当前的last指回root就行了?? ...
- bzoj 3277 串 && bzoj 3473 字符串 && bzoj 2780 [Spoj]8093 Sevenk Love Oimaster——广义后缀自动机
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3277 https://www.lydsy.com/JudgeOnline/problem.p ...
- 【BZOJ3227】串【广义后缀自动机】
题意 给出n个字符串,问每个字符串中有多少子串是这所有的n个字符串中至少k个的子串. 分析 广义后缀自动机模板题.对这n个串建广义后缀自动机,对于每个状态维护两个值cou[u]和lcu[u]分别代表拥 ...
随机推荐
- 01_Storm体系概要
1. Storm发展历史 Storm历史 1. 2010年12月,backtype公司Nathan,提出Storm的核心概念2. backtype, 提供数据分析,数据处理服务的一个公司3. 2011 ...
- Codeforces Round #279 (Div. 2) B. Queue
B. Queue time limit per test 2 seconds memory limit per test 256 megabytes input standard input outp ...
- 【程序员笔试面试必会——排序②】Python实现 计数排序、基数排序
一.计数排序 概要: 时间复杂度O(n),空间复杂度O(k),k是输入序列的值的范围(最大值-最小值),是稳定的.计数排序一般用于已知输入值的范围相对较小,比如给公司员工的身高体重信息排序. 思路: ...
- 设计模式--组合模式C++实现
组合模式C++实现 1定义 将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性 2类图 角色分析 Component抽象构建角色 定义参加组合独享的共同方 ...
- Java获取未知类型对象的属性
获取未知类型对象的属性通常有两种方式: 一是通过自定义注解的方式,通过获取被注解的属性从而获取属性的值,这种方式也是Spring参数注入的重要实现手段 二是通过反射获取属性的名称,通过属性名从而获取属 ...
- (2) iOS开发之UI处理-UILabel篇
我们经常要根据内容去动态计算控件的高度,比如一个UILabel控件,常常要显示多行内容,并且计算出总高度,如果每个UILabel要多行显示,都要写这么一段代码是非常痛苦的,看代码如下: 我想大 ...
- Hadoop出现 Wrong FS: hdfs://......错误的解决方法
今天在hadoop项目中出现以下报错:java.lang.IllegalArgumentException: Wrong FS: hdfs://......,expected: file:///... ...
- Prism5.0开发人员指南内容(纯汉语版)
Prism指南包含以下内容: 下载并安装Prism Prism5.0新内容 介绍 初始化应用程序 组件间的依赖管理 模块化应用程序开发 实现MVVM模式 进击的MVVM 组合式用户界面 导航 松耦合组 ...
- Hrbust 1535 相爱
Description 静竹在斐波那契的帮助下,渐渐的和数学相爱了.和数学在一起最有意思的就是它能够出一些特别有意思并且巧妙的题目让静竹来思考.这次也不例外,给静竹两个数a,b,又给出了加,减,乘,除 ...
- Markdown_04_折叠语法
目录 一.折叠语法 参考资料 一.折叠语法 主要使用的是 html5的 details标签 (1)示例如下: <details> <summary>折叠文本</summa ...