Luogu P3966 [TJOI2013]单词
题目链接 \(Click\) \(Here\)
本题\(AC\)自动机写法的正解之一是\(Fail\)树上跑\(DP\)。
\(AC\)自动机是\(Trie\)树和\(Fail\)树共存的结构,前者可以方便地处理前缀问题,而在后者中,一个节点的子节点,代表以当前字符串为后缀的所有字符串节点(根节点外向\(Fail\)树)。我们最初给每个串的所有前缀计数\(+1\),后期统计时,在该前缀的所有后缀上(\(Fail\)树上的祖先节点上),将其自身答案累加上去,就是总共出现的次数。
#include <bits/stdc++.h>
using namespace std;
const int N = 1000010;
struct AC_Auto {
int top, sta[N];
long long sum[N];
int cnt, ch[N][26], pre[N], fail[N];
AC_Auto () {
cnt = top = 0;
memset (ch, 0, sizeof (ch));
memset (sum, 0, sizeof (sum));
memset (pre, 0, sizeof (pre));
memset (fail, 0, sizeof (fail));
}
void add_str (char *s) {
int l = strlen (s), now = 0;
for (int i = 0; i < l; ++i) {
if (!ch[now][s[i] - 'a']) {
ch[now][s[i] - 'a'] = ++cnt;
}
pre[ch[now][s[i] - 'a']] = now;
now = ch[now][s[i] - 'a'];
sum[now]++;
}
sta[++top] = now;
}
queue <int> q;
void build () {
for (int i = 0; i < 26; ++i) {
if (ch[0][i]) {
q.push (ch[0][i]);
}
}
while (!q.empty ()) {
int u = q.front (); q.pop ();
for (int i = 0; i < 26; ++i) {
if (ch[u][i]) {
q.push (ch[u][i]);
fail[ch[u][i]] = ch[fail[u]][i];
} else {
ch[u][i] = ch[fail[u]][i];
}
}
}
}
int _cnt, head[N];
struct edge {
int nxt, to;
}e[N];
void add_edge (int from, int to) {
e[++_cnt].nxt = head[from];
e[_cnt].to = to;
head[from] = _cnt;
}
void dp (int u) {
for (int i = head[u]; ~i; i = e[i].nxt) {
dp (e[i].to);
sum[u] += sum[e[i].to];
}
}
void get_ans () {
_cnt = 0;
memset (head, -1, sizeof (head));
for (int i = 1; i <= cnt; ++i) {
add_edge (fail[i], i);
}
dp (0);
for (int i = 1; i <= top; ++i) {
cout << sum[sta[i]] << endl;
}
}
}AC;
int n; char s[N];
int main () {
cin >> n;
for (int i = 1; i <= n; ++i) {
scanf ("%s", s);
AC.add_str (s);
}
AC.build ();
AC.get_ans ();
}
\(UPD:\)新增了后缀数组\(+ST\)表\(+\)倍增写法
#include <bits/stdc++.h>
using namespace std;
const int N = 2000010;
char tmp[N];
int n, len, ban = 'z', s[N], id[N], sa[N], tp[N], rk[N], _rk[N], bin[N], _len[N], height[N];
void get_height (int n) {
int k = 0;
for (int i = 1; i <= n; ++i) {
if (k != 0) --k;
int j = sa[rk[i] - 1];
while (s[i + k] == s[j + k]) ++k;
height[rk[i]] = k;
}
}
void base_sort (int n, int m) {
for (int i = 0; i <= m; ++i) bin[i] = 0;
for (int i = 1; i <= n; ++i) bin[rk[tp[i]]]++;
for (int i = 1; i <= m; ++i) bin[i] += bin[i - 1];
for (int i = n; i >= 1; --i) sa[bin[rk[tp[i]]]--] = tp[i];
}
void suffix_sort (int n, int m) {
for (int i = 1; i <= n; ++i) {
tp[i] = i, rk[i] = s[i];
}
base_sort (n, m);
for (int w = 1; w <= n; w <<= 1) {
int cnt = 0;
for (int i = n - w + 1; i <= n; ++i) tp[++cnt] = i;
for (int i = 1; i <= n; ++i) if (sa[i] > w) tp[++cnt] = sa[i] - w;
base_sort (n, m);
memcpy (_rk, rk, sizeof (rk));
rk[sa[1]] = cnt = 1;
for (int i = 2; i <= n; ++i) {
rk[sa[i]] = (_rk[sa[i - 1]] == _rk[sa[i]]) && (_rk[sa[i - 1] + w] == _rk[sa[i] + w]) ? cnt : ++cnt;
}
if (cnt == n) break;
m = cnt;
}
}
int fa[N][25];
int query (int l, int r) {
if (l >= r) return 0; l++;
int mx = log2 (r - l + 1);
return min (fa[l][mx], fa[r - (1 << mx) + 1][mx]);
}
void get_STlist (int n) {
int mx = log2 (n);
for (int i = 1; i <= n; ++i) fa[i][0] = height[i];
for (int i = 1; i <= mx; ++i) {
for (int j = 1; j <= n - (1 << i) + 1; ++j) {
fa[j][i] = min (fa[j][i - 1], fa[j + (1 << (i - 1))][i - 1]);
}
}
}
int main () {
cin >> n;
for (int i = 1; i <= n; ++i) {
scanf ("%s", tmp);
int l = strlen (tmp);
id[i] = len + 1;
_len[i] = l;
for (int j = 0; j < l; ++j) {
s[++len] = tmp[j];
}
s[++len] = ++ban;
}
suffix_sort (len, ban);
get_height (len);
get_STlist (len);
for (int i = 1; i <= n; ++i) {
int l = rk[id[i]], r = rk[id[i]];
for (int j = 24; j >= 0; --j) {
int tol = l - (1 << j);
int tor = r + (1 << j);
if (tol >= 1 && query (tol, rk[id[i]]) >= _len[i]) l = tol;
if (tor <= len && query (rk[id[i]], tor) >= _len[i]) r = tor;
}
printf ("%d\n", r - l + 1);
}
}
Luogu P3966 [TJOI2013]单词的更多相关文章
- 洛谷P3966 [TJOI2013]单词(fail树性质)
P3966 [TJOI2013]单词 题目链接:https://www.luogu.org/problemnew/show/P3966 题目描述 小张最近在忙毕设,所以一直在读论文.一篇论文是由许多单 ...
- P3966 [TJOI2013]单词
P3966 [TJOI2013]单词 题目描述 小张最近在忙毕设,所以一直在读论文.一篇论文是由许多单词组成但小张发现一个单词会在论文中出现很多次,他想知道每个单词分别在论文中出现了多少次. 输入输出 ...
- 洛谷P3966 [TJOI2013]单词(AC自动机)
题目描述 小张最近在忙毕设,所以一直在读论文.一篇论文是由许多单词组成但小张发现一个单词会在论文中出现很多次,他想知道每个单词分别在论文中出现了多少次. 输入输出格式 输入格式: 第一行一个整数N,表 ...
- 洛谷P3966 [TJOI2013]单词(后缀自动机)
传送门 统计单词出现次数……为啥大家都是写AC自动机的嘞……明明后缀自动机也能做的说…… 统计出现次数这个就直接按长度排序然后做个dp就好,这是SAM的板子的要求啊,不提了 然后考虑怎么让所有串之间隔 ...
- [洛谷P3966][TJOI2013]单词
题目大意:有$n$个字符串,求每个字符串在所有字符串中出现的次数 题解:$AC$自动机,每个节点被经过时$sz$加一,每一个字符串出现次数为其$fail$树子树$sz$和 卡点:$AC$自动机根节点为 ...
- 【洛谷】3966:[TJOI2013]单词【AC自动机】【fail树】
P3966 [TJOI2013]单词 题目描述 小张最近在忙毕设,所以一直在读论文.一篇论文是由许多单词组成但小张发现一个单词会在论文中出现很多次,他想知道每个单词分别在论文中出现了多少次. 输入输出 ...
- BZOJ 3172: [Tjoi2013]单词 [AC自动机 Fail树]
3172: [Tjoi2013]单词 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 3198 Solved: 1532[Submit][Status ...
- 【BZOJ3172】[Tjoi2013]单词 AC自动机
[BZOJ3172][Tjoi2013]单词 Description 某人读论文,一篇论文是由许多单词组成.但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次. Input ...
- 3172: [Tjoi2013]单词
3172: [Tjoi2013]单词 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 3246 Solved: 1565[Submit][Status ...
随机推荐
- 转 在PowerDesigner的PDM图形窗口中显示数据列的中文注释
Name是名称(字段描述),Code是字段名称,Comment是注释名称,ER图中显示的是Name.一般设计时,Name跟comment都设计成描述, 而设计时候常把comment写成中文,name保 ...
- JS--bom对象:borswer object model浏览器对象模型
bom对象:borswer object model浏览器对象模型 navigator获取客户机的信息(浏览器的信息) navigator.appName;获得浏览器的名称 window:窗口对象 a ...
- Windows 7 SP1 x64 LSP
NALapi.dll napinsp.dll pnrpnsp.dll mswsock.dll winrnr.dll
- Newton方法
Newton方法主要解决无等式约束和等式约束的最优化方法. 1.函数进行二阶泰勒展开近似 Taylor近似函数求导等于0进而得到Newton步径.(搜索方向) 2.Newton减量(停止条件) 当1/ ...
- linux下如何安装mysql和redis
linux下如何安装mysql(mariadb) linux下如何安装软件? 1. yum安装软件也得注意,一个是配置yum源 1.我们当前的是阿里云的yum源(下载速度特别快) 通过 yum ins ...
- [代码]--给任意网站添加聊天功能,随时聊(fa)天(che)
感谢“topurl.cn”制作此功能并分享. 这是一段代码,在打开的网页中使用,可以加载一个外挂形式的聊天室功能, 就可以和同样访问此网站进行相同操作的网友进行聊(fa)天(che)了. 使用方法: ...
- 安卓Android基础—第一天
1.1G-4G的介绍 1G 大哥大 2G 小灵通 采用gsm标准(美国军方标准民用化) 发短信 3G 沃 72M/s 4G lte 100M/s 5G 华为 10G/s 小公司卖茶品大公司卖版权(标准 ...
- Codeforces518 D. Ilya and Escalator
传送门:>Here< 题意:有n个人排队做电梯,每个人必须等前面的人全部上了以后才能上.对于每秒钟,有p的概率选择上电梯,(1-p)的概率选择不上电梯.现在问t秒期望多少人上电梯 解题思路 ...
- python爬取豆瓣前25个影片内容的正则表达式练习
通过python正则表达式获取豆瓣top250的第一页的25个影片排名,影片名字,影片连接,导演,主演,上映日期,国家,剧情,评分,评价人数的内容 网页html内容: <ol class=&qu ...
- 【XSY2470】lcm 数学
题目大意 \(t\)组询问, 每组询问给定\(n\),求\(\sum_{k=1}^n[n,k]\),其中\([a,b]\)表示\(a\)和\(b\)的最小公倍数 . \(t\leq 300000,n\ ...