• 【题解】单词


    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;
    }
    
  • 相关阅读:
    IntelliJ IDEA 常用设置讲解
    Maven
    FileStram文件正由另一进程使用,该进程无法访问该文件,解决方法
    IIS 调用Microsoft.Office.Interop.Word.Documents.Open 返回为null
    .NET 中的 async/await 异步编程
    PHP表单验证内容是否为空
    PHP中的魔术变量
    PHP中的function函数详解
    PHP中的循环while、do...while、for、foreach四种循环。
    利用switch语句进行多选一判断。
  • 原文地址:https://www.cnblogs.com/h-lka/p/12189422.html
Copyright © 2020-2023  润新知