题目

给定n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串?

输入格式

第一行两个整数n,k。

接下来n行每行一个字符串。

输出格式

一行n个整数,第i个整数表示第i个字符串的答案。

输入样例

3 1

abc

a

ab

输出样例

6 1 3

提示

对于 100% 的数据,1<=n,k<=105,所有字符串总长不超过105,字符串只包含小写字母。

题解

我们先建一个广义后缀自动机

然后用每个原串在SAM上走,走到的节点就是parent树的叶子节点,将其沿parent边一直往上+1,表示这些节点表示的字符串+1【当然只能加一次,所以再开一个数组cur[]表示加过没有】

处理完后,我们就可以统计答案了

先拓扑排序,设f[]为该位置满足题意的字符串个数,显然如果一个位置累加的字符串>=k,那么该位置表示的至少为\(step[u] - step[pre[u]]\)

但还不完全,父亲的代表的字符串个数同样也符合该点

然后每个串再在SAM上走一遍统计答案即可

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cmath>
  4. #include<string>
  5. #include<cstring>
  6. #include<algorithm>
  7. #define LL long long int
  8. #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
  9. #define REP(i,n) for (int i = 1; i <= (n); i++)
  10. #define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
  11. using namespace std;
  12. const int maxn = 200005,maxm = 100005,INF = 1000000000;
  13. inline int read(){
  14. int out = 0,flag = 1; char c = getchar();
  15. while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
  16. while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
  17. return out * flag;
  18. }
  19. string s[maxn];
  20. char ss[maxn];
  21. int ch[maxn][26],pre[maxn],step[maxn],sz[maxn],cnt,last,n,k,cur[maxn];
  22. LL f[maxn];
  23. int ins(int x){
  24. int p = last,np = ++cnt; step[np] = step[p] + 1; last = np;
  25. while (p && !ch[p][x]) ch[p][x] = np,p = pre[p];
  26. if (!p) pre[np] = 1;
  27. else {
  28. int q = ch[p][x];
  29. if (step[q] == step[p] + 1) pre[np] = q;
  30. else {
  31. int nq = ++cnt; step[nq] = step[p] + 1;
  32. for (int i = 0; i < 26; i++) ch[nq][i] = ch[q][i];
  33. pre[nq] = pre[q]; pre[np] = pre[q] = nq;
  34. while (ch[p][x] == q) ch[p][x] = nq,p = pre[p];
  35. }
  36. }
  37. return np;
  38. }
  39. int b[maxn],a[maxn];
  40. LL ans;
  41. void tsort(){
  42. REP(i,cnt) b[step[i]]++;
  43. REP(i,cnt) b[i] += b[i - 1];
  44. for (int i = cnt; i; i--) a[b[step[i]]--] = i;
  45. }
  46. int main(){
  47. n = read(); k = read();
  48. last = cnt = 1;
  49. for (int i = 1; i <= n; i++){
  50. last = 1;
  51. scanf("%s",ss); s[i] = string(ss);
  52. int len = strlen(ss);
  53. for (int i = 0; i < len; i++) ins(ss[i] - 'a');
  54. }
  55. int u;
  56. for (int i = 1; i <= n; i++){
  57. u = 1;
  58. for (int j = 0; j < s[i].length(); j++){
  59. u = ch[u][s[i][j] - 'a'];
  60. for (int p = u; p && cur[p] != i; p = pre[p])
  61. sz[p]++,cur[p] = i;
  62. }
  63. }
  64. tsort();
  65. sz[1] = 0;
  66. for (int i = 1; i <= cnt; i++)
  67. u = a[i],f[u] = f[pre[u]] + (sz[u] >= k ? step[u] - step[pre[u]] : 0);
  68. for (int i = 1; i <= n; i++){
  69. ans = 0; u = 1;
  70. for (int j = 0; j < s[i].length(); j++){
  71. u = ch[u][s[i][j] - 'a'];
  72. ans += f[u];
  73. }
  74. printf("%lld ",ans);
  75. }
  76. return 0;
  77. }

BZOJ3473 字符串 【广义后缀自动机】的更多相关文章

  1. BZOJ3473 字符串 广义后缀自动机

    今天主攻了下SAM 好多东西以前都没理解到 对于这道题 我们建一个自动机存所有串 每个穿last从1开始 对于自动机上每个点额外记一个cnt 表示能匹配到这个点的不同串个数 建完对每个串在自动机上匹配 ...

  2. 【bzoj3277/bzoj3473】串/字符串 广义后缀自动机

    题目描述 字符串是oi界常考的问题.现在给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串(注意包括本身). 输入 第一行两个整数n,k.接下来n行每行一个 ...

  3. BZOJ 3473: 字符串 [广义后缀自动机]

    3473: 字符串 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 354  Solved: 160[Submit][Status][Discuss] ...

  4. BZOJ 3277 串 & BZOJ 3473 字符串 (广义后缀自动机、时间复杂度分析、启发式合并、线段树合并、主席树)

    标签那么长是因为做法太多了... 题目链接: (bzoj 3277) https://www.lydsy.com/JudgeOnline/problem.php?id=3277 (bzoj 3473) ...

  5. 2018.12.22 bzoj3473: 字符串(后缀自动机+启发式合并)

    传送门 调代码调的我怀疑人生. 启发式合并用迭代写怎么都跑不过(雾 换成了dfsdfsdfs版本的终于过了233. 题意简述:求给出nnn个字串,对于每个给定的字串求出其有多少个字串在至少kkk个剩下 ...

  6. BZOJ 3473 字符串 ——广义后缀自动机

    这题就比较有趣了. 首先匹配一遍,然后统计子树叶子节点中包含大于等于k的节点个数(HH的项链) 然后就可以搞了. 关于合法的情况数,显然是l[i]-l[fa[i]],然后向下下传即可(YY一下). # ...

  7. 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 ...

  8. BZOJ 3926: [Zjoi2015]诸神眷顾的幻想乡 广义后缀自动机 后缀自动机 字符串

    https://www.lydsy.com/JudgeOnline/problem.php?id=3926 广义后缀自动机是一种可以处理好多字符串的一种数据结构(不像后缀自动机只有处理一到两种的时候比 ...

  9. [bzoj3277==bzoj3473]出现k次子串计数——广义后缀自动机+STL

    Brief Description 给定n个字符串,对于每个字符串,您需要求出在所有字符串中出现次数大于等于k次的子串个数. Algorithm Design 先建立一个广义后缀自动机,什么是广义后缀 ...

随机推荐

  1. Eclipse介绍

    Eclipse是著名的跨平台开源集成开发环境(IDE).最初主要用来Java语言开发.Eclipse的本身只是一个框架平台,通过插件使其作为C/C++.Python.PHP等其他语言的开发工具.Ecl ...

  2. linux各文件夹的作用(转)

    转自:http://www.cnblogs.com/amboyna/archive/2008/02/16/1070474.html linux下的文件结构,看看每个文件夹都是干吗用的/bin 二进制可 ...

  3. vijos 1524 最小监视代价

    背景 看到Vijos上此类型的题目较少,特地放一道上来给大家练练. 描述 由于yxy小朋友做了一些不该做的事,他被jzp关进了一个迷宫里.由于jzp最近比较忙,疏忽大意了一些,yxy可以在迷宫中任意走 ...

  4. 洛谷 P1340 兽径管理

    题目描述 约翰农场的牛群希望能够在 N 个(1<=N<=200) 草地之间任意移动.草地的编号由 1到 N.草地之间有树林隔开.牛群希望能够选择草地间的路径,使牛群能够从任一 片草地移动到 ...

  5. 想转行做web前端工程师,必学这5大技能!知道是那些吗?

    web前端工程师是近几年才发展出来的新兴职业,也是目前火爆且高薪的职业. 大需求的市场环境下,出现了越来越多的人群转行做web前端工程师,如设计师.后台程序员.网虫.大学其他专业.策划.编辑等等. 要 ...

  6. OpenCascade:屏闪问题。

    1.在OnDraw中同时调用用V3d_View::Redaw()和 V3d_View::FitAll();可暂时解决. 2.在OnDraw中同时调用用V3d_View::Update();

  7. OpenCV2:介绍

    一.OpenCV简介 OpenCV所有的类和函数都在cv命名空间里面,可以用 using namespace cv; #include "opencv2/opencv.hpp" 1 ...

  8. ubuntu frp 自编译。本文不能按顺序来 请自己理解

    go run:go run 编译并直接运行程序,它会产生一个临时文件(但不会生成 .exe 文件),直接在命令行输出程序执行结果,方便用户调试. go build:go build 用于测试编译包,主 ...

  9. HTML5拖放(drag和drog)作品

    <!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...

  10. common-configuration的一些应用

    此程序依赖commons-configuration-1.6.jar和commons-lang-2.6.jar两个jar包. 需要先在工程的src目录下建立如下几个文件: config.propert ...