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 ...
随机推荐
- mybatis-spring-1.2.2.jar下载地址
http://www.java2s.com/Code/Jar/m/Downloadmybatisspring120jar.htm
- 当页面上需要的字段不在model中时候,需要自行设置该字段
当页面上需要的字段不在model中时候,需要自行设置该字段
- JarvisOJ Basic veryeasyRSA
已知RSA公钥生成参数: p = 3487583947589437589237958723892346254777 q = 8767867843568934765983476584376578389 ...
- #194 sequence(搜索+动态规划+主席树)
考虑按顺序暴搜子序列.如果序列中的数两两不同,显然每次给上一个找到的子序列添上后缀最小值,即为下一个要找的子序列.如果不能再加了就回溯继续考虑后缀次小.第三小……值,直到找到k个子序列. 有重复的数后 ...
- Quartus prime 16.0 中通过JTAG固化程序
前言 下载项目sof文件到开发板中,掉电后会消失:由于开发板有JTAG口,则可以用JTAG固化jic文件到EPCS16芯片中. 流程 1.打开quartus软件并打开convert programmi ...
- 【BZOJ3809】Gty的二逼妹子序列 莫队 分块
题目描述 给你一个长度为\(n\)的数列,还有\(m\)个询问,对于每个询问\((l,r,a,b)\),输出区间\([l,r]\)有多少范围在\([a,b]\)的权值. \(n\leq 100000, ...
- MT【249】离心率两题
椭圆$\dfrac{x^2}{a^2}+\dfrac{y^2}{b^2}=1,(a>b>0)$的一个焦点为$F$,过$F$的直线交椭圆于$A,B$两点,$M$是点$A$关于原点的对称点.若 ...
- 【BZOJ2940】条纹(博弈论)
[BZOJ2940]条纹(博弈论) 题面 BZOJ 神TM权限题. 题解 我们把题目看成取石子的话,题目就变成了这样: 有一堆\(m\)个石头,每次可以取走\(c,z,n\)个,每次取完之后可以把当前 ...
- 537. Complex Number Multiplication
题目大意: 给出a, b两个用字符串表示的虚数,求a*b 题目思路: 偷了个懒,Python3的正则表达式匹配了一下,当然acm里肯定是不行的 class Solution: def complexN ...
- SFTP多文件上传,删除
公司项目中需要把项目的相关文件上传到服务器的tomcat中,需要在项目中进行以下几步操作: 1.添加项目信息,包括名称,描述,服务器ip,sftp的用户名,密码,端口号等,存在配置,部署,删除等操作 ...