BZOJ_3172_[Tjoi2013]单词_后缀自动机

Description

某人读论文,一篇论文是由许多单词组成。但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次。

Input

第一个一个整数N,表示有多少个单词,接下来N行每行一个单词。每个单词由小写字母组成,N<=200,单词长度不超过10^6

Output

输出N个整数,第i行的数字表示第i个单词在文章中出现了多少次。

Sample Input

3
a
aa
aaa

Sample Output

6
3
1

用AC自动机的话应该会比较好写吧。https://www.cnblogs.com/suika/p/9128027.html
这里尝试了下后缀自动机。相当于查询某个子串出现了多少次。
两种写法,建立广义后缀自动机或者中间用'{'分隔开。
我比较喜欢前者,好写且方便。
方法1:插入时标记每个串最后出现的节点位置,然后DP即可。
代码:
#include <cstdio>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 1000050
int ch[N<<1][26],fa[N<<1],dep[N<<1],cnt=1,lst,n,flg[N];
int ws[N<<1],a[N<<1],siz[N<<1];
char w[N];
void insert(int x) {
int p=lst,np,q,nq;
if(ch[p][x]) {
q=ch[p][x];
if(dep[q]==dep[p]+1) lst=q;
else {
fa[nq=++cnt]=fa[q]; lst=nq;
dep[nq]=dep[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[q]=nq;
for(;p&&ch[p][x]==q;p=fa[p]) ch[p][x]=nq;
}
}else {
np=++cnt; lst=np; dep[np]=dep[p]+1;
for(;p&&!ch[p][x];p=fa[p]) ch[p][x]=np;
if(!p) fa[np]=1;
else {
q=ch[p][x];
if(dep[q]==dep[p]+1) fa[np]=q;
else {
fa[nq=++cnt]=fa[q];
dep[nq]=dep[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[q]=fa[np]=nq;
for(;p&&ch[p][x]==q;p=fa[p]) ch[p][x]=nq;
}
}
}
}
int main() {
scanf("%d",&n);
int i,j;
for(i=1;i<=n;i++) {
scanf("%s",w+1);
lst=1;
for(j=1;w[j];j++) insert(w[j]-'a'),siz[lst]++;
flg[i]=lst;
}
for(i=1;i<=cnt;i++) ws[dep[i]]++;
for(i=1;i<=cnt;i++) ws[i]+=ws[i-1];
for(i=cnt;i;i--) a[ws[dep[i]]--]=i;
for(i=cnt;i;i--) {
int p=a[i];
siz[fa[p]]+=siz[p];
}
for(i=1;i<=n;i++) {
printf("%d\n",siz[flg[i]]);
}
}

方法2:注意每个串对应的结点不一定是一开始插入的那个结点。

需要每次找一遍,比较麻烦。

代码:

#include <cstdio>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 2000050
int ch[N<<1][27],fa[N<<1],dep[N<<1],cnt=1,lst=1,n,flg[N];
int ws[N<<1],a[N<<1],siz[N<<1],l[233],r[233];
char w[N],s[N];
void insert(int x) {
int p=lst,np=++cnt,q,nq;
lst=np; dep[np]=dep[p]+1;
for(;p&&!ch[p][x];p=fa[p]) ch[p][x]=np;
if(!p) fa[np]=1;
else {
q=ch[p][x];
if(dep[q]==dep[p]+1) fa[np]=q;
else {
fa[nq=++cnt]=fa[q];
dep[nq]=dep[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[q]=fa[np]=nq;
for(;p&&ch[p][x]==q;p=fa[p]) ch[p][x]=nq;
}
}
}
void print() {
int i,j;
printf("test-------------------------------------------\n");
for(i=1;i<=cnt;i++) {
printf("p=%d,siz=%d,dep=%d,fa=%d\n",i,siz[i],dep[i],fa[i]);
for(j=0;j<=26;j++) {
if(ch[i][j]) {
printf("ch(%d)(%c)=%d\n",i,j+'a',ch[i][j]);
}
}
}
printf("lst=%d\n",lst);
}
int main() {
scanf("%d",&n);
int i,j,tot=0;
for(i=1;i<=n;i++) {
scanf("%s",w+1);
l[i]=tot+1;
for(j=1;w[j];j++) s[++tot]=w[j]-'a';
r[i]=tot;
s[++tot]=26;
}
for(i=1;i<=tot;i++) insert(s[i]),siz[lst]++;
// printf("%d\n",flg[2]);
// print();
for(i=1;i<=cnt;i++) ws[dep[i]]++;
for(i=1;i<=cnt;i++) ws[i]+=ws[i-1];
for(i=1;i<=cnt;i++) a[ws[dep[i]]--]=i;
for(i=cnt;i;i--) {
int p=a[i];
siz[fa[p]]+=siz[p];
}
for(i=1;i<=n;i++) {
int p=1;
// printf("%d %d\n",l[i],r[i]);
for(j=l[i];j<=r[i];j++) p=ch[p][s[j]];
// printf("p=%d\n",p);
printf("%d\n",siz[p]);
}
}
方法

BZOJ_3172_[Tjoi2013]单词_后缀自动机的更多相关文章

  1. 洛谷P3966 [TJOI2013]单词(后缀自动机)

    传送门 统计单词出现次数……为啥大家都是写AC自动机的嘞……明明后缀自动机也能做的说…… 统计出现次数这个就直接按长度排序然后做个dp就好,这是SAM的板子的要求啊,不提了 然后考虑怎么让所有串之间隔 ...

  2. 【BZOJ】3172: [Tjoi2013]单词(后缀自动机)

    http://www.lydsy.com/JudgeOnline/problem.php?id=3172 随便搞个sam就行了.(其实一开始看到数据n<=200, 单词长度不超过1e6,然后感觉 ...

  3. BZOJ_3172_[Tjoi2013]单词_AC自动机

    BZOJ_3172_[Tjoi2013]单词_AC自动机 Description 某人读论文,一篇论文是由许多单词组成.但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次. ...

  4. BZOJ_3238_[Ahoi2013]差异_后缀自动机

    BZOJ_3238_[Ahoi2013]差异_后缀自动机 Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 Sample Input cacao Sam ...

  5. BZOJ_4199_[Noi2015]品酒大会_后缀自动机

    BZOJ_4199_[Noi2015]品酒大会_后缀自动机 Description 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品 酒家”和“首席 ...

  6. BZOJ_4566_[Haoi2016]找相同字符_后缀自动机

    BZOJ_4566_[Haoi2016]找相同字符_后缀自动机 Description 给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数.两个方案不同当且仅当这两 个子串中有 ...

  7. BZOJ_3998_[TJOI2015]弦论_后缀自动机

    BZOJ_3998_[TJOI2015]弦论_后缀自动机 Description 对于一个给定长度为N的字符串,求它的第K小子串是什么. Input 第一行是一个仅由小写英文字母构成的字符串S 第二行 ...

  8. BZOJ_2099_[Usaco2010 Dec]Letter 恐吓信_后缀自动机+贪心

    BZOJ_2099_[Usaco2010 Dec]Letter 恐吓信_后缀自动机 Description FJ刚刚和邻居发生了一场可怕的争吵,他咽不下这口气,决定佚名发给他的邻居 一封脏话连篇的信. ...

  9. BZOJ3172&&lg3966 TJOI单词(广义后缀自动机)

    BZOJ3172&&lg3966 TJOI单词(广义后缀自动机) 题面 自己找去 HINT 给出多个文本串,让你查找每个文本串一共出现了多少次,广义后缀自动机建出parent tree ...

随机推荐

  1. [POJ2443]Set Operation(bitset)

    传送门 题意:给出n个集合(n<=1000),每个集合中最多有10000个数,每个数的范围为1~10000,给出q次询问(q<=200000),每次给出两个数u,v判断是否有一个集合中同时 ...

  2. 【思维+贪心】codeforces Game of the Rows

    http://codeforces.com/contest/839/problem/B [题意] 给定n组人,告诉每组人的人数,这些人要在飞机上坐座位 飞机上座位的分布看图可以知道,12  3456 ...

  3. JAVA实现选择排序,插入排序,冒泡排序,以及两个有序数组的合并

    一直到大四才开始写自己的第一篇博客,说来实在有点羞愧.今天写了关于排序的算法题,有插入排序,冒泡排序,选择排序,以下贴上用JAVA实现的代码: public class test5 { public ...

  4. jquery 关于ajax 及其son

    <%@ page language="java" pageEncoding="UTF-8"%><%@include file="/c ...

  5. maven 新建项目时修改默认jre路径

    新建maven项目时,JRE System Library默认为J2SE-1.5 如果想修改为1.7,修改maven的settings.xml ,在profiles中添加 <profile> ...

  6. grails的criteria和hql查询

    grails在查询方面也保留了hibernate的hql和criteria查询功能.hql自然不必多说基本不会有什么变化,grails的criteria查询在hibernate上面做了微调使用起来更加 ...

  7. [转]JAVA异常

    异常 异常就是导致程序中断执行的一段指令流. 在java中, 对于异常在API中也有明确的定义,叫做异常类. Error : JVM的错误, 程序中不进行处理, 交给虚拟机. Exception : ...

  8. Office EXCEL 表格如何设置某个单元格是选择项,如何设置一级下拉菜单

    1 比如我要在C这一列都做成下拉菜单,则我选中这一列的第一个单元格,然后点击数据-有效性,然后把允许改成"序列",在来源中输入每一项(用逗号隔开),比如我一共要做四个下拉菜单选项, ...

  9. webpack-Manifest

    Manifest 在使用 webpack 构建的典型应用程序或站点中,有三种主要的代码类型: 你或你的团队编写的源码. 你的源码会依赖的任何第三方的 library 或 "vendor&qu ...

  10. java SE基础(Collection接口概述)

    Collection接口相关集成关系例如以下图 1. 关于可迭代接口(Iterable)             可迭代接口仅包括一个方法,返回一个在一组T类型元素上进行迭代的迭代器: public ...