题解单词

Posted h-lka

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解单词相关的知识,希望对你有一定的参考价值。

LuoguP3966

题目大意:给定若干个字符串,求它们组成的文章中,每个单词出现的次数。输入有重复。

(Solution)#:

多模式匹配,直接上(AC)自动机咯。但是注意到,因为有重复,所以造成建立自动机的时候,(Trie)上的字符串编号会被覆盖。对答案造成错误影响。

那么我们可以人工去重,记录一下每个重复的串的最早编号,用最早编号替代即可。

那么考虑(TLE)问题。

对于一些(Trie)上的点,显然有些点我们重复走过而且多次跳过失配指针。这显然是浪费时间的。

那我们用两个数组(apr,vis)分别记录一个节点出现的次数以及当前节点是否被统计过。

那么,走到一个节点(u)时,看看它是否走过,没走过就一次性把它产生的所有答案统计掉。如果走过显然就不用再走了。(vis)数组标记判断。

这题就这么做完了。

(Code:)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<queue>
using namespace std;
const int MAXN=1e6+10;
const int N=201;
char S[MAXN];
namespace AC{
    int cnt[N],tot,tr[MAXN][26],apr[MAXN];
    int fail[MAXN],idx[MAXN],vis[MAXN];
    int sm[N];
    void Ins(char *s,int pos){
        int u=0;
        for(int i=1;s[i];++i){
            int x=s[i]-'a';
            if(!tr[u][x])tr[u][x]=++tot;
            u=tr[u][x];apr[u]++;
        }
        if(idx[u])sm[pos]=idx[u];
        else idx[u]=pos;
    }
    queue<int>q;
    void build(){
        for(int i=0;i<26;++i)
            if(tr[0][i])q.push(tr[0][i]);
        while(!q.empty()){
            int u=q.front();
            q.pop();
            for(int i=0;i<26;++i){
                if(tr[u][i])
                    fail[tr[u][i]]=tr[fail[u]][i],q.push(tr[u][i]);
                else tr[u][i]=tr[fail[u]][i];
            }
        }
    }
    void query(char *t){
        int u=0;
        for(int i=1;t[i];++i){
            int x=t[i]-'a';
            u=tr[u][x];
            for(int j=u;j;j=fail[j])
                if(idx[j]&&!vis[u])cnt[idx[j]]+=apr[u];
            vis[u]=1;
        }
    }
}
int n;
char s[N][MAXN];
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i)scanf("%s",s[i]+1),AC::Ins(s[i],i); 
    AC::build();
    for(int i=1;i<=n;++i)if(!AC::sm[i])AC::query(s[i]); 
    for(int i=1;i<=n;++i)printf("%d
",AC::sm[i]?AC::cnt[AC::sm[i]]:AC::cnt[i]);
    return 0;
}

以上是关于题解单词的主要内容,如果未能解决你的问题,请参考以下文章

编写一个程序, 将 a.txt 文件中的单词与 b.txt 文件中的 单词交替合并到 c.txt 文件中, a.txt 文件中的单词用回车符 分隔, b.txt 文件中用回车或空格进行分隔。(代码片段

如果我想从另一个片段中添加书签,为啥我的书签单词没有保存到 sqlite 数据库?

LeetCode 79. 单词搜索c++/java详细题解

洛谷 P1101 单词方阵题解

如何通过C#中的特定片段从句子中提取整个单词?

PHP 很短的片段:PHP单词剪切