#3831 TJOI2013单词

WOJ#3831 TJOI2013单词

题面

  某人读论文,一篇论文是由许多单词组成。但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次。

输入

  第一个一个整数 N ,表示有多少个单词,接下来 N 行每行一个单词。

输出

  输出 N 个整数,第 i 行的数字表示第 i 个单词在文章中出现了多少次。

样例输入

  3
  a
  aa
  aaa

样例输出

  6
  3
  1

提示

  对于全部数据,1≤N≤200 ,所有单词长度的和不超过 106,保证每个单词由小写字母组成。

题解

  本题中,第2行到第N+1行构成论文,同时每一行也是单词,所以我们可以用AC自动机求解,依次用每一个单词进行匹配,每次匹配到一个单词的结尾时,就在ans数组中对应这个结尾的单词序号的位置记录答案。

  但是想一想就会发现上述方法不但会超时,还可能在单词出现重复时出错(Trie树上记录单词结尾时只能记录一个单词的序号,遇到重复时重复单词会因此得到0,笔者最初就是因为没考虑这一点而错误)。因此我们可以用一个sme数组来记录每一种单词的序号,同时在Trie树上记录单词结尾时记录这种单词的序号。再进一步思考可以发现,如果我们把每个单词的重复次数用tim数组记录下来,就可以避免因重复查询带来的超时。

代码

#include<bits/stdc++.h>
using namespace std;
#define N 1000010
int n,tot,ans[N],nxt[N],sme[N],tim[N],vis[N],ch[N][30];
char CH[210][50010];
void build(char *s,int ord){
    int u=1,len=strlen(s);
    for(int i=0;i< len;i++){
        int c=s[i]-‘a‘;
        if(!ch[u][c]){ch[u][c]=++tot;memset(ch[tot],0,sizeof(ch[tot]));}
        u=ch[u][c];
    }
    if(!vis[u]){vis[u]=ord;sme[ord]=ord;tim[ord]=1;}
    else{sme[ord]=vis[u];tim[vis[u]]++;}
    return ;
}
void bfs(){
    queue<int>q;
    for(int i=0;i<=25;i++) ch[0][i]=1;
    q.push(1);nxt[1]=0;
    while(!q.empty()){
        int u=q.front();q.pop();
        for(int i=0;i<=25;i++){
            if(!ch[u][i]){ch[u][i]=ch[nxt[u]][i];continue;}
            q.push(ch[u][i]);
            int v=nxt[u];nxt[ch[u][i]]=ch[v][i];
        }
    }
}
void find(char *s,int num){
    int u=1,len=strlen(s);
    for(int i=0;i<=len;i++){
        int c=s[i]-‘a‘,k=ch[u][c];
        while(k>1){
            if(vis[k]) ans[vis[k]]+=num;
            k=nxt[k];
        }
        u=ch[u][c];
    }
    return ;
}
int main(){
    scanf("%d",&n);tot=1;
    for(int i=1;i<=n;i++){scanf("%s",CH[i]);build(CH[i],i);}
    bfs();
    for(int i=1;i<=n;i++){if(sme[i]==i) find(CH[i],tim[i]);}
    for(int i=1;i<=n;i++){printf("%d\n",ans[sme[i]]);}
    return 0;
}

原文地址:https://www.cnblogs.com/doyo2019/p/10849643.html

时间: 2024-10-21 14:06:06

#3831 TJOI2013单词的相关文章

【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

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

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

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

BZOJ 3172: [Tjoi2013]单词 &&  BZOJ 2434 [Noi2011]阿狸的打字机 (施工中)

fail树 链接地址 定义 把所有fail指针逆向,这样就得到了一棵树 (因为每个节点的出度都为1,所以逆向后每个节点入度为1,所以得到的是一棵树) 还账… 有了这个东西,我们可以做很多事… 对于AC自动机的构造前面的文章已经讲了,而在查询的时候,有一点感觉没有说清楚: 对于x串在y串中出现,必然是在y串某个前缀的后缀与x串相同 fail指针指向与该节点表示串后缀相等的且长度最大的串(或前缀)的节点 然后,根据fail指针的原理,在查询的时候,沿着当前节点的fail指针向上查找,直到root结束

BZOJ 题目3172: [Tjoi2013]单词(AC自动机||AC自动机+fail树||后缀数组暴力||后缀数组+RMQ+二分等五种姿势水过)

3172: [Tjoi2013]单词 Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 1890  Solved: 877 [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