【TJOI2013】单词

Description

给定若干模式串组成的文本串,求每个模式串出现的次数。

Solution

由于模式串可能重复,所以直接按照AC自动机的模板会出错,所以我们定义一个same数组,end数组只记录最早的编号,每次如果要覆盖,便把令该节点的same值为这个位置上的end的值,查询一遍,输出答案就输出ans[same[i]]。

我们再定义两个数组vis和sum表示当前节点有没有被扫过,当前节点被覆盖的次数。那么在统计答案的时候,如果当前节点是某个模式串的结尾并且没有扫过,那么说明这个模式串有贡献,就将答案+sum[now],之后将vis赋值为1,这样跑一边AC自动机就可以了。

Code

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 int n, tot, same[100010], ans[100010], ch[500010][26], end[500010], vis[500010], sum[500010];
 4 int f[500010];
 5 char c[210][100010];
 6 inline int read() {
 7     int ret = 0, op = 1;
 8     char c = getchar();
 9     while (!isdigit(c)) {
10         if (c == '-') op = -1; 
11         c = getchar();
12     }
13     while (isdigit(c)) {
14         ret = ret * 10 + c - '0';
15         c = getchar();
16     }
17     return ret * op;
18 }
19 inline void write(int x) {
20     if (x < 0) putchar('-'), x = -x;
21     if (x >= 10) write(x / 10);
22     putchar(x % 10 + '0');
23 }
24 void insert(char *a, int id) {
25     int now = 0, l = strlen(a);
26     for (int i = 0; i < l; ++i) {
27         if (!ch[now][a[i] - 'a']) ch[now][a[i] - 'a'] = ++tot;
28         now = ch[now][a[i] - 'a'];
29         sum[now]++;
30     }
31     if (!end[now]) end[now] = id;
32     else same[id] = end[now];
33 }
34 queue <int> q;
35 void bfs() {
36     for (register int i = 0; i < 26; ++i)
37         if (ch[0][i]) {
38             f[ch[0][i]] = 0;
39             q.push(ch[0][i]);
40         }
41     while (!q.empty()) {
42         int now = q.front();
43         q.pop();
44         for (register int i = 0; i < 26; ++i) {
45             if (ch[now][i]) f[ch[now][i]] = ch[f[now]][i], q.push(ch[now][i]);
46             else ch[now][i] = ch[f[now]][i];
47         }
48     }
49 }
50 void query(char *a) {
51     int now = 0;
52     int l = strlen(a);
53     for (int i = 0; i < l; ++i) {
54         now = ch[now][a[i] - 'a'];
55         for (register int j = now; j; j = f[j])
56             if (end[j] && !vis[now]) ans[end[j]] += sum[now];
57         vis[now] = 1;
58     }
59 }
60 int main() {
61     n = read();
62     for (register int i = 1; i <= n; ++i) {
63         scanf("%s", c[i]);
64         insert(c[i], i);
65     }
66     bfs();
67     for (register int i = 1; i <= n; ++i) 
68         if (!same[i]) query(c[i]);
69     for (register int i = 1; i <= n; ++i) {
70         if (!same[i]) write(ans[i]);
71         else write(ans[same[i]]);
72         puts("");
73     }
74     return 0;
75 }
AC Code

 

转载于:https://www.cnblogs.com/shl-blog/p/11262780.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值