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;
    }
    
  • 相关阅读:
    Transition 过渡/转场动画(一)
    动态创建类/ swizzle class
    Protocol协议分发器
    UITableView 支持左右滑动(二)
    UITableView 支持左右滑动(一)
    CATiledLayer显示超大图片的解决方案
    ReplicatorLayer 复制图层
    iOS OpenGL ES简单绘制纹理
    iOS OpenGL ES简单绘制三角形
    Mac定时执行脚本_服务launchctl
  • 原文地址:https://www.cnblogs.com/yinyuqin/p/15393729.html
Copyright © 2011-2022 走看看