BZOJ3277 串(后缀自动机)
对多串建立SAM的一种方法是加分隔符。于是加完分隔符建出SAM。
考虑统计出每个节点被多少个串包含。让每个串各自在SAM上跑,跑到一个节点就标记(显然一定会完全匹配该节点,因为是对包含其的串建的SAM)并暴跳fail,遇到已经被该串标记过的点就停止。
这样暴力的复杂度容易感性证明是O(Lsqrt(L))(L即所有串总长度),因为暴力一个串的过程中,SAM每个点至多被标记一次,每一步跳fail的次数也显然不会超过该串长度,于是对该串的复杂度是min(L,|S|2)(S即该串长度),总的最劣复杂度大约就是sqrt(L)个长度为sqrt(L)的串时取得,且常数极小。当然也可以使用树剖实现,不用分析复杂度就能知道是O(Llog2L)。
然后递推求出每个点被经过时的具体贡献,也即其到parent树的根的路径上所有出现在至少k个串中的点的len-lenfa值的和。再对每个串各自跑一遍累加所经过点的贡献即可。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define N 400010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
int x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
int n,m,k,s[N],l[N],r[N],son[N][27],q[N],tot[N],fail[N],len[N],f[N],g[N],cnt=1,last=1;
char qwq[N];
bool flag[N];
vector<int> a;
void ins(int c)
{
int x=++cnt,p=last;last=x;len[x]=len[p]+1;
while (!son[p][c]&&p) son[p][c]=x,p=fail[p];
if (!p) fail[x]=1;
else
{
int q=son[p][c];
if (len[q]==len[p]+1) fail[x]=q;
else
{
int y=++cnt;
len[y]=len[p]+1;
memcpy(son[y],son[q],sizeof(son[q]));
fail[y]=fail[q],fail[x]=fail[q]=y;
while (son[p][c]==q) son[p][c]=y,p=fail[p];
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
const char LL[]="%I64d ";
#else
const char LL[]="%lld ";
#endif
n=read(),k=read();
for (int i=1;i<=n;i++)
{
scanf("%s",qwq+1);
int _=strlen(qwq+1);
l[i]=m+1,r[i]=m+_;
for (int j=1;j<=_;j++) s[++m]=qwq[j]-'a';
s[++m]=26;
}
for (int i=1;i<=m;i++) ins(s[i]);
for (int i=1;i<=n;i++)
{
int k=1;
for (int j=l[i];j<=r[i];j++)
{
while (!son[k][s[j]]) k=fail[k];
if (!k) k=1;
else
{
k=son[k][s[j]];
for (int x=k;!flag[x];x=fail[x])
flag[x]=1,f[x]++,a.push_back(x);
}
}
for (int j:a) flag[j]=0;a.clear();
}
for (int i=1;i<=cnt;i++) tot[len[i]]++;
for (int i=1;i<=m;i++) tot[i]+=tot[i-1];
for (int i=1;i<=cnt;i++) q[tot[len[i]]--]=i;
for (int i=1;i<=cnt;i++)
{
int x=q[i];
g[x]=g[fail[x]];
if (f[x]>=k) g[x]+=len[x]-len[fail[x]];
}
for (int i=1;i<=n;i++)
{
ll ans=0;int k=1;
for (int j=l[i];j<=r[i];j++)
{
while (!son[k][s[j]]) k=fail[k];
if (!k) k=1;
else k=son[k][s[j]],ans+=g[k];
}
printf(LL,ans);
}
return 0;
}
BZOJ3277 串(后缀自动机)的更多相关文章
- BZOJ 2946: [Poi2000]公共串( 后缀自动机 )
一个串建后缀自动机, 其他串在上面跑, 然后用当前串跑的去更新全部 ------------------------------------------------------------------ ...
- bzoj 2946 [Poi2000]公共串——后缀自动机
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2946 对每个串都建一个后缀自动机,然后 dfs 其中一个自动机,记录同步的话在别的自动机上走 ...
- 【bzoj2946】[Poi2000]公共串 后缀自动机
[Poi2000]公共串 Time Limit: 3 Sec Memory Limit: 128 MBSubmit: 1386 Solved: 620[Submit][Status][Discus ...
- BZOJ 2946 [Poi2000]公共串 ——后缀自动机
任意选择一个串作为模式串,构建出后缀自动机. 然后用其他的串在后缀自动机上跑匹配. 然后就到了理解后缀自动机性质的时候. 在某一个节点的最大值是可以沿着parent树上传的. 然后用dp[i][j]表 ...
- bzoj 2946 公共串 —— 后缀自动机
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2946 建出 n-1 个后缀自动机一起跑呗. 代码如下: #include<cstdio ...
- bzoj3277 串 (后缀数组+二分答案+ST表)
常见操作:先把所有串都连到一起,但中间加上一个特殊的符号(不能在原串中/出现过)作为分割 由于全部的子串就等于所有后缀的所有前缀,那我们对于每一个后缀,去求一个最长的前缀,来满足这个前缀在至少K个原串 ...
- BZOJ 2946 POI2000 公共串 后缀自动机(多串最长公共子串)
题意概述:给出N个字符串,每个串的长度<=2000(雾...可能是当年的年代太久远机子太差了),问这N个字符串的最长公共子串长度为多少.(N<=5) 抛开数据结构,先想想朴素做法. 设计一 ...
- BZOJ 3676 [Apio2014]回文串 (后缀自动机+manacher/回文自动机)
题目大意: 给你一个字符串,求其中回文子串的长度*出现次数的最大值 明明是PAM裸题我干嘛要用SAM做 回文子串有一个神奇的性质,一个字符串本质不同的回文子串个数是$O(n)$级别的 用$manach ...
- BZOJ2946 [Poi2000]公共串(后缀自动机)
Description 给出几个由小写字母构成的单词,求它们最长的公共子串的长度. 任务: l 读入单词 l 计算最长公共子串的长度 l 输 ...
- BZOJ 3676: [Apio2014]回文串 后缀自动机 Manacher 倍增
http://www.lydsy.com/JudgeOnline/problem.php?id=3676 过程很艰难了,第一次提交Manacher忘了更新p数组,超时,第二次是倍增的第0维直接在自动机 ...
随机推荐
- Python3报错:ModuleNotFoundError: No module named '_bz2'
系统信息 系统:CentOS Linux release 7.6.1810 (Core) python版本:python3.7 报错信息 from _bz2 import BZ2Compresso ...
- 微信小程序+php 授权登陆,完整代码
先上图 实现流程: 1.授权登陆按钮和正文信息放到了同一个页面,未授权的时候显示登陆按钮,已授权的时候隐藏登陆按钮,显示正文信息,当然也可以授权和正文分开成两个页面,在授权页面的onlo ...
- django-配置404页面
setting.py文件配置 # SECURITY WARNING: don't run with debug turned on in production! DEBUG = False ALLOW ...
- JDK8 Steam流操作
原文:https://github.com/niumoo/jdk-feature/blob/master/src/main/java/net/codingme/feature/jdk8/Jdk8Str ...
- xampp1.8.3 配置 php5.x 访问 SQL Server 2008
1.安装xampp 2.下载php sqlsrv扩展 Microsoft Drivers 3.2 for PHP for SQL Server 官方下载地址: http://www.microsoft ...
- udp,select超时和recvfrom收不到数据原因
wirshark抓包,发现有数据.但是select超时,直接recvfrom又失败. 代码中需要改进:select超时后,会移除fd_set集合中超时的那个句柄,所以每次要重新进行FD_SET,然后再 ...
- linux虚拟机获取不到ip的解决方法 --
问题描述: 在win10操作系统上,安装了centos7 虚拟机,安装后,用wifi网络可以获取ip,但是切换到手机热点或有线网络就获取不到ip 解决办法: 按照一般的修改ONBOOT =yes, 然 ...
- HS编码查询hs海关编码列表
HS编码查询是外面人一个必须技能,以下是ytkah整理的hs海关编码列表,罗列了几乎所有的hs商品编码,方便大家查询,也欢迎大家转给有需要的朋友! 编号 名称 01022100 荷斯坦青年牛 0103 ...
- 13-cmake语法-路径设置
路径设置: 包括头文件路径.库文件路径.库文件名等 INCLUDE_DIRECTORIES 向工程添加多个特定的头文件搜索路径,路径之间用空格分隔,如果路径包含空格,可以使用双引号将它括起来,默认的行 ...
- 07-cmake语法-MATCHES
如果给定的字串或变量值域给定的正则表达式匹配的话,表达式返回真. IF (CMAKE_SYSTEM_NAME MATCHES "Linux") MESSAGE(STATUS &qu ...