• CF235C_Cyclical Quest


    很好的一个自动机的题目。

    给原串,和若干个询问串。求原串里有多少个不同子串可以通过询问串循环移动得到。

    有点类似求两个串的lcs,但是灵活一点。

    首先我们把询问串长度扩大一倍,去掉最后一个字符。因为最后那个字符结尾的情况已经有了。

    然后把这个新串拿到SAM中跑一遍,跑的过程就像求lcs差不多,每次判断长度len是否大于询问串长度,以及节点有没有重复加入,来更新答案就好了。

    前面自动机的构建以及拓扑排序处理就不说了。

    召唤代码君:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define maxn 4002000
    using namespace std;
    
    char s[maxn];
    int next[maxn][26],pre[maxn],step[maxn],g[maxn],tag[maxn];
    int cnt[maxn],Q[maxn];
    int N,last,ans,n,L;
    int p,q,np,nq;
    
    void insert(int x)
    {
    	np=++N,p=last,step[np]=step[p]+1,last=np,g[np]=1;
    	while (p!=-1 && next[p][x]==0) next[p][x]=np,p=pre[p];
    	if (p==-1) return;
    	q=next[p][x];
    	if (step[q]==step[p]+1) { pre[np]=q; return; }
    	nq=++N,step[nq]=step[p]+1,pre[nq]=pre[q];
    	for (int i=0; i<26; i++) next[nq][i]=next[q][i];
    	pre[np]=pre[q]=nq;
    	while (p!=-1 && next[p][x]==q) next[p][x]=nq,p=pre[p];  
    }
    
    void process()
    {
    	for (int i=1; i<=N; i++) cnt[step[i]]++;
    	for (int i=2; i<=N; i++) cnt[i]+=cnt[i-1];
    	for (int i=1; i<=N; i++) Q[--cnt[step[i]]]=i;
    	for (int i=N-1; i>=0; i--) g[pre[Q[i]]]+=g[Q[i]];
    }
    
    int main()
    {
    	pre[0]=-1;
    	scanf("%s",s);
    	for (int i=0; s[i]; i++) insert(s[i]-'a');
    	process();
    	scanf("%d",&n);
    	for (int T=1; T<=n; T++)
    	{
    		ans=0;
    		scanf("%s",s+1);
    		L=strlen(s+1);
    		for (int i=1; i<L; i++) s[i+L]=s[i];
    		s[L+L]='';
    		int cur=0,len=0;
    		for (int i=1; s[i]; i++)
    		{
    			
    			int k=s[i]-'a';
    			while (cur!=-1 && next[cur][k]==0) len=min(len,step[cur]),cur=pre[cur];
    			if (cur==-1) { cur=0; continue; }
    			len=min(len,step[cur])+1;
    			cur=next[cur][k];
    			for (; step[pre[cur]]>=L; len=min(len,step[cur])) cur=pre[cur];
    			if (len>=L && tag[cur]!=T) ans+=g[cur],tag[cur]=T;
    		}
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    

      

    如有转载,请注明出处(http://www.cnblogs.com/lochan)
  • 相关阅读:
    多线程 分配
    fopen:文本和二进制方式打开方式对比【转】
    C优先级列表【转】
    sscanf用法
    heap和stack【转】
    大端小端【转】
    二级指针与二维数组的秘密【二者不等】
    C++中的空类编译器默认隐式声明哪些成员函数【CSDN】
    项目内存泄漏问题及解决方案后续
    浅谈部门前台框架中的几个方法<一>
  • 原文地址:https://www.cnblogs.com/lochan/p/3803669.html
Copyright © 2020-2023  润新知