zoukankan      html  css  js  c++  java
  • 洛谷 P5357 【模板】AC自动机(二次加强版)

    传送门


    解题思路

    来pyyz过掉的第一题祭
    一开始在前来个模板上改了改,发现T飞了。

    看一下题解发现,因为标记不会清空,所以会被卡到O(ST)。

    于是考虑优化。

    因为AC自动机本质上是一个有向无环图,所以考虑每次更新答案时只更新到当前节点,最后拓扑排序遍历一遍图统计答案即可。

    复杂度降到了O(S+T)。

    AC代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<map>
    using namespace std;
    const int maxn=2e5+5;
    string s[maxn];
    int n,cnt,p[maxn],tot,ans[maxn],tr[maxn][30],fail[maxn],in[maxn],anss[maxn];
    vector<int> num[maxn];
    struct node{
    	int v,next;
    }e[maxn];
    void insert(int u,int v){
    	in[v]++;
    	cnt++;
    	e[cnt].v=v;
    	e[cnt].next=p[u];
    	p[u]=cnt;
    }
    void work(){
    	queue<int> q; 
    	for(int i=1;i<maxn;i++){
    		if(in[i]==0) q.push(i);
    	}
    	while(!q.empty()){
    		int u=q.front();q.pop();
    		for(int i=p[u];i!=-1;i=e[i].next){
    			int v=e[i].v;
    			ans[v]+=ans[u];
    			in[v]--;
    			if(in[v]==0) q.push(v);
    		}
    	}
    }
    void update(string s,int id){
    	int now=0,len=s.length();
    	for(int i=0;i<len;i++){
    		int k=s[i]-'a';
    		if(tr[now][k]) now=tr[now][k];
    		else{
    			tr[now][k]=++tot;
    			now=tot;
    		}
    	}
    	num[now].push_back(id);
    }
    void build(){
    	queue<int> q;
    	for(int i=0;i<26;i++){
    		if(tr[0][i]) q.push(tr[0][i]);
    	}
    	while(!q.empty()){
    		int now=q.front();q.pop();
    		for(int i=0;i<26;i++){
    			if(tr[now][i]){
    				fail[tr[now][i]]=tr[fail[now]][i],q.push(tr[now][i]);
    				insert(tr[now][i],fail[tr[now][i]]);
    			}
    			else tr[now][i]=tr[fail[now]][i];
    		}
    	}
    }
    void query(string s){
    	int now=0,len=s.length();
    	for(int i=0;i<len;i++){
    		now=tr[now][s[i]-'a'];
    		if(now){
    			ans[now]++;
    		}
    	}
    }
    int main(){
    	//freopen(".in","r",stdin);
    	//freopen(".out","w",stdout);
    	ios::sync_with_stdio(false);
    	memset(p,-1,sizeof(p));
    	cin>>n;
    	for(int i=1;i<=n;i++) cin>>s[i],update(s[i],i);
    	build();
    	cin>>s[n+1];
    	query(s[n+1]);
    	work();
    	for(int i=1;i<maxn;i++){
    		int k=num[i].size();
    		for(int j=0;j<k;j++) anss[num[i][j]]+=ans[i];
    	}
    	for(int i=1;i<=n;i++){
    		cout<<anss[i]<<endl;
    	}
    	return 0;
    }
    
  • 相关阅读:
    faked 一个用于 mock 后端 API 的轻量工具
    分享开源 Markdown 编辑器 Mditor 的「桌面版」
    一个 MVC 框架以 MVVM 之「魂」复活了!
    简单的内存缓存模块
    Node 多进程并发控制小模块
    Confman
    用 Nokitjs 解决前端开发中的跨域问题
    LEK分布式日志系统搭建
    hello world2
    hello world!
  • 原文地址:https://www.cnblogs.com/yinyuqin/p/15393729.html
Copyright © 2011-2022 走看看