3277: 串
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 309 Solved: 118
[Submit][Status][Discuss]
Description
字符串是oi界常考的问题。现在给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串(注意包括本身)。
Input
第一行两个整数n,k。
接下来n行每行一个字符串。 Output
输出一行n个整数,第i个整数表示第i个字符串的答案。 Sample Input
3 1
abc
a
ab Sample Output
6 1 3 HINT
对于100%的数据,n,k,l<=100000

算法讨论:

首先对这些串建立出广义后缀自动机,同时在建立的时候要保存当前结点都是哪些串的子串,然后建立出Parent树,

对树进行一遍DFS,把一个点的所以后代结点的颜色信息全部合并到自己身上,并用一个数组来维护当前结点有多少颜色,也就是多少个串的子串。

因为我们知道,一个点在Parent树上的父亲结点是其的最长后缀,所以如果一个点有颜色Q,那么其所有祖先结点全部有颜色Q。

然后对于每个串跑自动机,如果一个当前结点的颜色数目小于K,就沿其fail指针向上跳,跳到一个大于等于K的地方,

此时答案应该加上min(这个点的len, 当前ln + 1的最小值)。 至于这个ln是做什么的,容我再想想。

代码:

#include <cstdlib>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <set>
#include <string> using namespace std;
const int N = 100000 + 5;
const int C = 26;
typedef long long ll; int n, cnt, k;
int head[N << 1], color[N << 1];
string s[N];
set <int> occ[N << 1];
set <int> :: iterator it; struct State {
int pre, len, next[C];
}st[N << 1]; struct SuffixAutomaton {
int sz, last; void Init() {
sz = last = 1;
st[sz].pre = -1; st[sz].len = 0;
sz ++;
} void add(int c, int ccc) {
int cur = sz ++, p;
st[cur].len = st[last].len + 1;
for(p = last; p != -1 && !st[p].next[c]; p = st[p].pre)
st[p].next[c] = cur;
if(p == -1) st[cur].pre = 1;
else {
int q = st[p].next[c];
if(st[q].len == st[p].len + 1) st[cur].pre = q;
else {
int cle = sz ++;
st[cle].pre = st[q].pre;
st[cle].len = st[p].len + 1;
for(int i = 0; i < C; ++ i) st[cle].next[i] = st[q].next[i];
for(; p != -1 && st[p].next[c] == q; p = st[p].pre)
st[p].next[c] = cle;
st[q].pre = st[cur].pre = cle;
}
}
last = cur;
occ[cur].insert(ccc);
}
}sam; struct Edge {
int from, to, next;
}edges[N << 1]; void insert(int from, int to) {
++ cnt;
edges[cnt].from = from; edges[cnt].to = to;
edges[cnt].next = head[from]; head[from] = cnt;
} void dfs(int u) {
for(int i = head[u]; i; i = edges[i].next) {
int v = edges[i].to;
dfs(v);
if(occ[u].size() < occ[v].size())
swap(occ[u], occ[v]);
for(it = occ[v].begin(); it != occ[v].end(); ++ it)
occ[u].insert(*it);
}
color[u] = occ[u].size();
} int main() {
//freopen("stringa.in", "r", stdin);
//freopen("stringa.out", "w", stdout); int __size__ = 50 << 20;
char *__p__ = (char*)malloc (__size__) + __size__;
__asm__("movl %0, %%esp" :: "r"(__p__)); //ios :: sync_with_stdio(false);
cin >> n >> k;
sam.Init();
for(int i = 1; i <= n; ++ i) {
cin >> s[i];
int len = s[i].length();
for(int j = 0; j < len; ++ j) sam.add(s[i][j] - 'a', i);
sam.last = 1;
}
for(int i = 1; i < sam.sz; ++ i)
if(st[i].pre != -1) insert(st[i].pre, i);
dfs(1);
for(int i = 1; i <= n; ++ i) {
if(k > n) { cout << 0 << " "; continue; }
ll ans = 0;
int p = 1, ln = 0, len;
len = s[i].length();
for(int j = 0; j < len; ++ j) {
p = st[p].next[(int) s[i][j] - 'a'];
while(color[p] < k) p = st[p].pre;
ln = min(ln + 1, st[p].len);
ans += ln;
}
cout << ans << " ";
} //fclose(stdin); fclose(stdout);
return 0;
}

BZOJ 3277 串 (广义后缀自动机)的更多相关文章

  1. BZOJ 3277/3473 广义后缀自动机

    说实话没啥难的. 建一棵广义后缀自动机,暴力自底向上更新即可. 时间复杂度非常玄学,但据说是可以过的. 要注意每个串中相同的子串的贡献是都要加进去的,开始因为这个被坑了好久 QAQ Code: #in ...

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

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

  3. BZOJ3277: 串(广义后缀自动机)

    Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1196  Solved: 478[Submit][Status][Discuss] Descripti ...

  4. BZOJ 2894: 世界线 广义后缀自动机

    Code: #include<bits/stdc++.h> #define maxn 300000 #define ll long long using namespace std; ve ...

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

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

  6. bzoj 3926 转换+广义后缀自动机

    思路:重点在于叶子节点只有20个,我们把叶子节点提到根,把20个trie图插入后缀自动机,然后就是算有多少个本质不同的字串. #include<bits/stdc++.h> #define ...

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

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

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

  9. bzoj 3277 & bzoj 3473,bzoj 2780 —— 广义后缀自动机

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3277 https://www.lydsy.com/JudgeOnline/problem.p ...

随机推荐

  1. ICP编程软件配置(烧写KEIL编译后的bin文件)

    1. 安装NuMicro_ICP_Programming_Tool_1.29.6425软件 2. 打开软件后选择目标芯片后点击“连接”按钮 3. 添加程序 4. 点击设定按钮进行设定 5. 点击开始 ...

  2. memcache运维整理

    memcache运维总结 第一部分:memcache安装 1.安装libevent 2.安装memcache 3.安装php的memcache扩展 4.测试 第二部分:memcache客户端操作 1. ...

  3. Python中*和**的用法

    好久不用Python,今天在用Python写个小工具的时候发现好些东西都快忘记了,特别是*和**. 什么情况下使用*和**呢(不是C里面的指针哦!) 当函数的参数不确定时,可以使用*args 和**k ...

  4. Android学习笔记--Broadcast, BroadcastReceiver(广播)

    参考资料:http://www.cnblogs.com/playing/archive/2011/03/23/1992030.html 在 Android 中使用 Activity, Service, ...

  5. Retrofit2.0+OkHttp打印Request URL(请求地址参数)

    学习了Retrofit中的拦截器功能:实现日志中打印请求头内容 Retrofit 2+ 是基于OKHttp进行封装的,那么也就是说想进行请求拦截然后进行打印出来的话,就必须要从OkHttp进行入手. ...

  6. AFNetworking 系列教程

      前几天发现iOS9.xcode7之后NSURLConnection的API被弃用了,取而代之的是NSURLSession,看到这我首先想到了AFNetworking,因为工程的所有网络请求都是基于 ...

  7. 《VIM-Adventures攻略》前言

    本文已转至http://cn.abnerchou.me/2014/03/02/bfdaadb0/ 自从有了计算机,人们就想向其灌输自己的想法. 要想对其输入,自然离不开文本编辑器. 公告:<VI ...

  8. 终于懂了:Delphi的函数名不是地址,取地址必须遵守Object Pascal的语法(Delphi和C的类比:指针、字符串、函数指针、内存分配等)good

    这点是与C语言不一样的地方,以前我一直都没有明白这一点,所以总是不明白:函数地址再取地址算怎么回事? ------------------------------------------------- ...

  9. SQLite数据库安装与使用

    SQLite是遵守ACID的关系数据库管理系统,它包含在一个相对小的C库中.它是D.RichardHipp创建的公有领域项目. 不像常见的客户端/服务器结构范例,SQLite引擎不是个程序与之通信的独 ...

  10. hdu1573:数论,线性同余方程组

    题目大意: 给定一个N ,m 找到小于N的  对于i=1....m,满足  x mod ai=bi  的 x 的数量. 分析 先求出 同余方程组 的最小解x0,然后 每增加lcm(a1...,am)都 ...