bzoj 3172 后缀数组|AC自动机

  后缀数组或者AC自动机都可以,模板题。


/**************************************************************
Problem: 3172
User: BLADEVIL
Language: C++
Result: Accepted
Time:424 ms
Memory:34260 kb
****************************************************************/

//By BLADEVIL
#include <cstdio>
#include <cstring>
#define maxn 2000010
#define maxm 300

using namespace std;

struct node{
int cnt;
node *fail,*child[30];
node(){
cnt=0; fail=NULL;
memset(child,0,sizeof child);
}
} *que[maxn],*root=new(node),*w[maxm];

int n;

int main(){
scanf("%d",&n);
for (int i=1;i<=n;i++){
char c[maxn];
scanf("%s",&c);
int len=strlen(c);
node *t=root;
for (int j=0;j<len;j++){
if (!t->child[c[j]-‘a‘]) t->child[c[j]-‘a‘]=new(node);
t=t->child[c[j]-‘a‘]; t->cnt++;
}
w[i]=t;
}
int h=0,t=1;
root->fail=root; que[1]=root;
while (h<t){
node *u=que[++h];
for (int i=0;i<26;i++) if (u->child[i]){
que[++t]=u->child[i];
node *v=u->fail;
que[t]->fail=v->child[i]&&v->child[i]!=que[t]?v->child[i]:root;
} else u->child[i]=u->fail->child[i];
}
for (int i=t;i;i--) que[i]->fail->cnt+=que[i]->cnt;
for (int i=1;i<=n;i++) printf("%d\n",w[i]->cnt);
return 0;
}


/**************************************************************
Problem: 3172
User: BLADEVIL
Language: C++
Result: Accepted
Time:6660 ms
Memory:107360 kb
****************************************************************/
//By BLADEVIL
#include <cstdio>
#include <cstring>
#include <algorithm>
#define maxn 1001000
#define maxm 300

using namespace std;

int n,len;
char s[maxn];
int sa[maxn],tsa[maxn],rk[maxn],trk[maxn],sum[maxn],h[maxn];
int w[maxn][21];
int adr[maxm],len_s[maxm];

inline void getsa(int j) {
for (int i=1;i<=len;i++) sum[i]=0;
for (int i=1;i<=len;i++) sum[rk[i+j]]++;
for (int i=1;i<=len;i++) sum[i]+=sum[i-1];
for (int i=len;i;i--) tsa[sum[rk[i+j]]--]=i;

for (int i=1;i<=len;i++) sum[i]=0;
for (int i=1;i<=len;i++) sum[rk[i]]++;
for (int i=1;i<=len;i++) sum[i]+=sum[i-1];
for (int i=len;i;i--) sa[sum[rk[tsa[i]]]--]=tsa[i];
}

inline int query(int l,int r) {
int i,j;
for (i=0,j=1;(j<<1)<=r-l+1;j<<=1,i++) ;
return min(w[l][i],w[r-j+1][i]);
}

int main() {
scanf("%d",&n); len=0;
for (int i=1;i<=n;i++) {
scanf("%s",s+len+1);
adr[i]=len+1;
len=strlen(s+1);
s[++len]=‘^‘;
len_s[i]=len-adr[i];
}
//for (int i=1;i<=len;i++) printf("%c",s[i]); printf("\n");
for (int i=1;i<=len;i++) sum[s[i]]++;
for (int i=1;i<=255;i++) sum[i]+=sum[i-1];
for (int i=len;i;i--) sa[sum[s[i]]--]=i;
rk[sa[1]]=1;
for (int i=2,p=1;i<=len;i++) {
if (s[sa[i]]!=s[sa[i-1]]) p++;
rk[sa[i]]=p;
}
for (int j=1;j<=len;j<<=1) {
getsa(j);
trk[sa[1]]=1;
for (int i=2,p=1;i<=len;i++) {
if (rk[sa[i]]!=rk[sa[i-1]]||rk[sa[i]+j]!=rk[sa[i-1]+j]) p++;
trk[sa[i]]=p;
}
for (int i=1;i<=len;i++) rk[i]=trk[i];
}
for (int i=1,j=0;i<=len;i++) {
if (rk[i]==1) continue;
while (i+j<=len&&sa[rk[i]-1]+j<=len&&s[i+j]==s[sa[rk[i]-1]+j]) j++;
h[rk[i]]=j;
if (j) j--;
}
//for (int i=1;i<=len;i++) printf("%d ",sa[i]); printf("\n");
//for (int i=1;i<=len;i++) printf("%d ",h[i]); printf("\n");
memset(w,127,sizeof w);
for (int i=1;i<=len;i++) w[i][0]=h[i];
for (int j=1,k=1;j<21;j++,k<<=1)
for (int i=1;i<=len;i++)
if (i+k<=len) w[i][j]=min(w[i][j-1],w[i+k][j-1]);
//for (int i=1;i<=len;i++) printf("%d ",w[i][2]); printf("\n");
//printf("%d\n",query(5,8));
//printf("%d\n",rk[6]);
for (int i=1;i<=n;i++) {
int l=1,r=rk[adr[i]],mid,left=rk[adr[i]],right=rk[adr[i]];
while (l<=r) {
mid=l+r>>1;
if (query(mid+1,rk[adr[i]])>=len_s[i])
left=mid,r=mid-1; else l=mid+1;
}
l=rk[adr[i]],r=len;
while (l<=r) {
mid=l+r>>1;
if (query(rk[adr[i]]+1,mid)>=len_s[i])
right=mid,l=mid+1; else r=mid-1;
}
printf("%d\n",right-left+1);
}
return 0;
}

bzoj 3172 后缀数组|AC自动机

时间: 2024-10-28 11:39:22

bzoj 3172 后缀数组|AC自动机的相关文章

BZOJ 3172: [Tjoi2013]单词 [AC自动机 Fail树]

3172: [Tjoi2013]单词 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 3198  Solved: 1532[Submit][Status][Discuss] Description 某人读论文,一篇论文是由许多单词组成.但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次. Input 第一个一个整数N,表示有多少个单词,接下来N行每行一个单词.每个单词由小写字母组成,N<=200,单词长度不超过10^6

BZOJ 3172: [Tjoi2013]单词 AC自动机

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 HINT 入门 #

BZOJ 3172:后缀数组

题意:给N个单词组成的文章,输出每一个单词出现的次数 思路:连接后求sa,对每一个单词求lcp>=len[i]的最大范围 加了二分也没有快多少.. #include"cstdio" #include"queue" #include"cmath" #include"stack" #include"iostream" #include"algorithm" #include"

BZOJ 3998 后缀数组

思路: 第一问 建出来后缀数组以后  前缀和一发n-sa[i]-ht[i]+1  二分 第二问 二分判断是带重复的第几 怎么判断呢   找到它  往后扫ht递减sum+=它   跟K判判 注意等于 加一 之类的各种坑爹细节 要死.. //By SiriusRen #include <bits/stdc++.h> using namespace std; const int N=1000050; int n,cntA[N],cntB[N],A[N],B[N],rk[N],sa[N],tsa[N]

BZOJ 1559: [JSOI2009]密码( AC自动机 + 状压dp )

建AC自动机后, dp(x, y, s)表示当前长度为x, 在结点y, 包括的串的状态为s的方案数, 转移就在自动机上走就行了. 对于输出方案, 必定是由给出的串组成(因为<=42), 所以直接暴搜答案. 数据范围很小, 可以AC(复杂度懒得算了....) ------------------------------------------------------------------------------------------------ #include<cstdio> #in

BZOJ 2553 BeiJing2011 禁忌 AC自动机+矩阵乘法

题目大意:给定n个模式串,定义一个字符串的伤害为所有子串的划分中最多包含的模式串数量,求长度为len的字符串的伤害期望值 小五prpr,恋恋prpr,大小姐prpr 首先建立AC自动机 令f[i][j]表示长度为i的字符串在AC自动机上的第j个节点的伤害期望值 如果要走到某个节点是危险节点或者fail指针指向危险节点,就ans++,然后回到根节点 这样构造出来的矩阵做快速幂= = 这么做都会把- - 不会别骂我- - 但是跑完发现找不到答案- - 因此我们需要稍微改造一下- - 新建一个节点 如

BZOJ 2938 Poi2000 病毒 AC自动机+拓扑排序

题目大意:给定n个01串,问是否存在一个无限长的01串,不包含这n个01串中的任何一个 建出Trie图之后判环即可 我这傻逼一开始居然跑了一个DFS去判环23333 #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 30300 using namespace std; int n; char s[M]; namespace Aho_C

bzoj 4119 后缀数组 + 并查集

并查集合并的时候更新信息.注意a[ i ] 有负的. #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<vector> #define LL long long #define LD long double #define ull unsigned long long #define fi first #define se second

【BZOJ4566】找相同字符(后缀数组)

[BZOJ4566]找相同字符(后缀数组) 题面 BZOJ 题解 后缀数组的做法,应该不是很难想 首先看到两个不同的串,当然是接在一起求\(SA,height\) 那么,考虑一下暴力 在两个串各枚举一个后缀,他们的\(lcp\)就是对答案产生的贡献 现在优化一下,按照\(SA\)的顺序枚举来处理\(lcp\) 利用一个单调栈维护一下,每次记录一下前面有多少个的贡献和当前答案一样就好啦 只是有点难写... #include<iostream> #include<cstdio> #in