• 【BZOJ3172】单词(AC自动机)


    【BZOJ3172】单词(AC自动机)

    题面

    Description

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

    Input

    第一个一个整数N,表示有多少个单词,接下来N行每行一个单词。每个单词由小写字母组成,N<=200,单词长度不超过10^6

    Output

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

    Sample Input

    3

    a

    aa

    aaa

    Sample Output

    6

    3

    1

    题解

    yyb因为调这道题而死亡

    在重复一下题目的意思把。。。
    看不见文章对不读,,
    那是因为文章就是所有单词组成的
    然后你就可以yy所有单词中间有一个空格之类的东西

    很明显的AC自动机,
    然后,我们
    每次把每个单词带进去匹配一下
    暴跳fail指针
    美滋滋的收获90分
    yyb炸裂了

    0分是空间玩炸了。。。

    暴跳fail指针是可以被卡炸的。。。
    所以,我们就不暴跳了呀
    每次要跳的时候就在这个点这里打一个标记
    所有标记打完之后
    我们就从底下往上一层层跳(记一下bfs序倒着跳)
    每次就只跳一层,然后标记丢到上面去
    这样就可以一起跳啦

    然后美滋滋的 AC啦

    对了,
    这题还有一点
    就是会有重复的单词。。。
    所以要记录一下每个单词和哪个单词是一样的(不是并查集)

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    #define MAX 1100000
    struct Node
    {
    	int vis[26];
    	int fail,ff;
    	int id,sum;
    }t[MAX];
    int tot,lid[500];
    int ans[500];
    int n,q[MAX],tp;
    char ch[MAX],ss[MAX];
    void Insert(int id,char *s)
    {
    	int gg=strlen(s);
    	int now=0;
    	for(int i=0;i<gg;++i)
    	{
    		if(!t[now].vis[s[i]-'a'])
    			t[now].vis[s[i]-'a']=++tot;
    		t[t[now].vis[s[i]-'a']].ff=now;
    		now=t[now].vis[s[i]-'a'];
    	}
    	if(!t[now].id)t[now].id=id,lid[id]=id;
    	else lid[id]=t[now].id;
    }
    queue<int> Q;
    void GetFail()
    {
    	for(int i=0;i<26;++i)
    		if(t[0].vis[i])
    			Q.push(q[++tp]=t[0].vis[i]);
    	while(!Q.empty())
    	{
    		int u=Q.front();Q.pop();
    		for(int i=0;i<26;++i)
    		{
    			if(t[u].vis[i])
    				t[t[u].vis[i]].fail=t[t[u].fail].vis[i],Q.push(q[++tp]=t[u].vis[i]);
    			else
    				t[u].vis[i]=t[t[u].fail].vis[i];
    		}
    	}
    }
    int l=0;
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;++i) 
    	{
    		scanf("%s",ch);
    		Insert(i,ch);
    		int len=strlen(ch);
    		for(int j=0;j<len;++j)
    			ss[l++]=ch[j];
    		ss[l++]='#';
    	}
    	GetFail();
    	int now=0;
    	for(int j=0;j<l;++j)
    	{
    		if(ss[j]=='#')now=0;
    		else now=t[now].vis[ss[j]-'a'];
    		t[now].sum++;
    	}
    	for(int i=tp;i;i--)
    	{
    		ans[t[q[i]].id]+=t[q[i]].sum;
    		t[t[q[i]].fail].sum+=t[q[i]].sum;
    	}
    	for(int i=1;i<=n;++i)printf("%d
    ",ans[lid[i]]);
    	return 0;
    }
    
    
  • 相关阅读:
    Jenkins获取运行job的用户名(在构建历史中展示构建人)
    Android -tool工具UIautomatorviewer提示“不能让屏幕黑屏”
    转: 谈谈关于内存的一些心得体会
    IP地址,子网掩码划分(转)
    重定向子进程控制台程序的输入输出
    正则表达式(1)
    Log4Net使用指南(转)
    使用wireshark抓本机之间的包(转)
    VirtualBox开发环境的搭建详解(转)
    SxsTrace工具使用方法(转)
  • 原文地址:https://www.cnblogs.com/cjyyb/p/8251584.html
Copyright © 2020-2023  润新知