zoukankan      html  css  js  c++  java
  • CF-GYM101741K. Consistent Occurrences

    CF-GYM101741K. Consistent Occurrences

    题意:给你一个长度为(n)的串(s),以及(m)次询问,每次给出一个串(t),询问(t)(s)中最多出现了多少次(出现不能重叠)。

    联想到前一题,我们可以将询问建树。

    我们可以自然地想到,当匹配成功后,直接跳回根节点(就像kmp一样)。但是,由于是多串匹配,该算法假掉了。

    这时候,我们看一道题:凌乱的yyy / 线段覆盖

    有人说,一道橙题,有什么好看的?

    思想可以借鉴。

    首先,每个匹配出来的出现位置,就相当于一条线段。而由于是顺序匹配,就默认左端点有序。因此,我们对于每个文本串,在(fin)这个(vector)内,不仅要存编号(id),也要存上一次出现的右端点(las)与文本串长度(len)

    则如果对于当前匹配的位置(i),有(lasle i),则这条线段就可以被覆盖上。

    (merge)代码:

    void merge(){
    	int x=1;
    	for(int i=0;i<S;i++){
    		x=t[x].ch[s[i]-'a'];
    		for(int y=x;y!=1;y=t[y].fail)for(int j=0;j<t[y].fin.size();j++)if(t[y].fin[j].las<=i)res[t[y].fin[j].id]++,t[y].fin[j].las=i+t[y].fin[j].len;
    	}
    }
    

    (记录文本串长度是为了方便推出右端点)

    并且,由于这题实在不好拓扑,就只写了暴力跳(fail)的程序(反正也能过)。

    总代码:

    #include<bits/stdc++.h>
    using namespace std;
    int n,m,S,res[100100],cnt=1;
    char s[100100],ss[100100];
    struct Query{
    	int id,las,len;
    	Query(int x=0,int y=0,int z=0){
    		id=x,las=y,len=z;
    	}
    };
    struct AC_Automaton{
    	int ch[26],fail;
    	vector<Query>fin;
    }t[100100];
    void ins(int id){
    	int x=1;
    	for(int i=0;i<S;i++){
    		if(!t[x].ch[ss[i]-'a'])t[x].ch[ss[i]-'a']=++cnt;
    		x=t[x].ch[ss[i]-'a'];
    	}
    	t[x].fin.push_back(Query(id,0,S));
    }
    queue<int>q;
    void build(){
    	for(int i=0;i<26;i++){
    		if(t[1].ch[i])t[t[1].ch[i]].fail=1,q.push(t[1].ch[i]);
    		else t[1].ch[i]=1;
    	}
    	while(!q.empty()){
    		int x=q.front();q.pop();
    		for(int i=0;i<26;i++){
    			if(t[x].ch[i])t[t[x].ch[i]].fail=t[t[x].fail].ch[i],q.push(t[x].ch[i]);
    			else t[x].ch[i]=t[t[x].fail].ch[i];
    		}
    	}
    }
    void merge(){
    	int x=1;
    	for(int i=0;i<S;i++){
    		x=t[x].ch[s[i]-'a'];
    		for(int y=x;y!=1;y=t[y].fail)for(int j=0;j<t[y].fin.size();j++)if(t[y].fin[j].las<=i)res[t[y].fin[j].id]++,t[y].fin[j].las=i+t[y].fin[j].len;
    	}
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	scanf("%s",s);
    	for(int i=1;i<=m;i++)scanf("%s",ss),S=strlen(ss),ins(i);
    	build(),S=n;
    	merge();
    	for(int i=1;i<=m;i++)printf("%d
    ",res[i]);
    	return 0;
    }
    
  • 相关阅读:
    Git查询
    HDU-3038 How Many Answers Are Wrong 并查集
    CodeForcesEducationalRound40-D Fight Against Traffic 最短路
    HDU-6109 数据分割 并查集(维护根节点)
    ZOJ-3261 Connections in Galaxy War 并查集 离线操作
    AtCoderBeginner091-C 2D Plane 2N Points 模拟问题
    HDU-1878 欧拉回路 欧拉回路
    [笔记-图论]Floyd
    [笔记-图论]Bellman-Ford
    [笔记-图论]Dijkstra
  • 原文地址:https://www.cnblogs.com/Troverld/p/12781173.html
Copyright © 2011-2022 走看看