bzoj3172 [Tjoi2013]单词

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3172

【题解】

考虑建出AC自动机,那么fail树上每个点的父亲为fail,父亲->儿子为后缀关系(父亲是儿子后缀)

那么走到父亲肯定走到了儿子,直接统计即可。

# include <queue>
# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm>
// # include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int M = 1.6e6 + 10;
const int mod = 1e9+7;

int n; char t[M];
int v[M], ps[M]; vector<int> G[M];
struct ACM {
    int ch[M][26], fail[M], siz, isend[M];
    inline void set() {siz = 0;}
    inline int ins(char *t) {
        int p = 0;
        for (int i=0; t[i]; ++i) {
            int c = t[i] - ‘a‘;
            if(!ch[p][c]) ch[p][c] = ++siz;
            p = ch[p][c];
            v[p] ++;
        }
        return p;
    }
    queue<int> q;
    inline void build() {
        while(!q.empty()) q.pop();
        for (int c=0; c<26; ++c) {
            int p = ch[0][c];
            if(p) {
                fail[p] = 0;
                q.push(p);
            }
        }
        while(!q.empty()) {
            int top = q.front(); q.pop();
            for (int c=0; c<26; ++c) {
                int p = ch[top][c];
                if(!p) {
                    ch[top][c] = ch[fail[top]][c];
                    continue;
                }
                q.push(p);
                int v = fail[top];
                while(v && !ch[v][c]) v = fail[v];
                fail[p] = ch[v][c];
            }
        }
    }
    inline void getfail() {
        for (int i=1; i<=siz; ++i)
            G[fail[i]].push_back(i);
    }
}S;

inline void dfs(int x) {
    for (int i=0; i<G[x].size(); ++i) {
        int y = G[x][i];
        dfs(y);
        v[x] += v[y];
    }
}

int main() {
    cin >> n; S.set();
    for (int i=1; i<=n; ++i) {
        scanf("%s", t);
        ps[i] = S.ins(t);
    }
    S.build();
    S.getfail();
    dfs(0);
    for (int i=1; i<=n; ++i) printf("%d\n", v[ps[i]]);
    return 0;
}

时间: 2024-08-05 15:08:47

bzoj3172 [Tjoi2013]单词的相关文章

BZOJ-3172: [Tjoi2013]单词 (AC自动姬)

3172: [Tjoi2013]单词 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 4057  Solved: 1964[Submit][Status][Discuss] Description 某人读论文,一篇论文是由许多单词组成.但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次. Input 第一个一个整数N,表示有多少个单词,接下来N行每行一个单词.每个单词由小写字母组成,N<=200,单词长度不超过10^6

[Bzoj3172][Tjoi2013]单词(fail树)

3172: [Tjoi2013]单词 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 4777  Solved: 2345[Submit][Status][Discuss] Description 某人读论文,一篇论文是由许多单词组成.但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次. Input 第一个一个整数N,表示有多少个单词,接下来N行每行一个单词.每个单词由小写字母组成,N<=200,单词长度不超过10^6

[bzoj3172][Tjoi2013]单词——AC自动机

题目大意: 某人读论文,一篇论文是由许多单词组成.但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次. 思路: 第i个单词在整个文章中出现了多少次即i串的结尾可以被多少个串的节点给跳到. 于是吧fail看成每个节点唯一的父亲,每个节点的权值为有多少个单词的前缀经过了它,然后直接统计子树内的权值和即可. #include<bits/stdc++.h> #define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++

[BZOJ3172 ][Tjoi2013]单词(AC自动机)

Description 不稳定的传送门 某人读论文,一篇论文是由许多单词组成.但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次.单词个数<=200,单词总长度<=10^6 Solution AC自动机的入门题,将所有单词建一颗字典树,并构造fail树 然后随便统计一下数量就可以了 Code #include <cstdio> #include <algorithm> #include <cstring> #define R re

BZOJ3172[Tjoi2013]单词 题解

题目大意: 求一些字符串在一段文章中出现的次数. 思路: AC自动机的经典应用,建完自动机直接将队列里的元素调Fail指针记录即可. 代码: 1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 using namespace std; 5 #define M 1000009 6 #define FC x==0?0:child[fail[x]][i] 7 char s[M]; 8 int head,t

【bzoj3172】: [Tjoi2013]单词 字符串-AC自动机

[bzoj3172]: [Tjoi2013]单词 先用所有单词构造一个AC自动机 题目要求的是每个单词在这个AC自动机里匹配到的次数 每次insert一个单词的时候把路径上的cnt++ 那么点p->cnt就是以root到p这条路径为前缀的单词的个数 如果p->fail指向了点q,那么就会对q点产生p->cnt的贡献(root到q一定为root到p的后缀) 最后递推统计完所有fail的贡献,找到关键点输出就可以了 1 /* http://www.cnblogs.com/karl07/ */

3172: [Tjoi2013]单词

3172: [Tjoi2013]单词 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 1424  Solved: 653[Submit][Status] Description 某人读论文,一篇论文是由许多单词组成.但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次. Input 第一个一个整数N,表示有多少个单词,接下来N行每行一个单词.每个单词由小写字母组成,N<=200,单词长度不超过10^6 Output 输出N

BZOJ 3172: [Tjoi2013]单词 AC自动机

3172: [Tjoi2013]单词 Description 某人读论文,一篇论文是由许多单词组成.但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次. Input 第一个一个整数N,表示有多少个单词,接下来N行每行一个单词.每个单词由小写字母组成,N<=200,单词长度不超过10^6 Output 输出N个整数,第i行的数字表示第i个单词在文章中出现了多少次. Sample Input 3 a aa aaa Sample Output 6 3 1 HINT 入门 #

bzoj 3172 [Tjoi2013]单词(fail树,DP)

3172: [Tjoi2013]单词 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 2327  Solved: 1093[Submit][Status][Discuss] Description 某人读论文,一篇论文是由许多单词组成.但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次. Input 第一个一个整数N,表示有多少个单词,接下来N行每行一个单词.每个单词由小写字母组成,N<=200,单词长度不超过10^6