• CF452E Three strings【广义SAM】


    传送门
    也是广义 SAM 的板子题,建好广义 SAM,统计 (epA,epB,epC),然后对于区间 (ans[len[fa[x]]+1],...,ans[len[x]]) 加上 (epA imes epB imes epC) 就行了,当然这个用差分实现简单快捷。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int N=3e5+10;
    const int mod=1e9+7;
    int A[N*2],B[N*2],C[N*2];
    LL ans[N];
    int slen,n=mod;
    char s[N];
    struct SuffixAutoMachine{
    	int tot=1,len[N*2],fa[N*2],ch[N*2][26],*epos,a[N*2],c[N];
    	int newnode(int x){fa[++tot]=fa[x];len[tot]=len[x];memcpy(ch[tot],ch[x],sizeof(ch[tot]));return tot;}
    	int extend(int p,int c){
    		int q=ch[p][c],nq=newnode(q);
    		len[nq]=len[p]+1;fa[q]=nq;
    		for(;p&&ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
    		return nq;
    	}
    	int append(int p,int c){
    		if(ch[p][c]) if(len[ch[p][c]]==len[p]+1) return ch[p][c];else return extend(p,c);
    		int np=newnode(0);len[np]=len[p]+1;
    		for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;
    		if(!p) fa[np]=1;
    		else if(len[ch[p][c]]==len[p]+1) fa[np]=ch[p][c];
    		else fa[np]=extend(p,c);
    		return np;
    	}
    	void insert(int *_epos){
    		int last=1;epos=_epos;
    		for(int i=1;i<=slen;i++) last=append(last,s[i]-'a'),epos[last]=1;
    	}
    	void solve(){
    		for(int i=1;i<=tot;i++) c[len[i]]++;
    		for(int i=1;i<N;i++) c[i]+=c[i-1];
    		for(int i=tot;i>=1;i--) a[c[len[i]]--]=i;
    		for(int i=tot;i>1;i--){
    			A[fa[a[i]]]+=A[a[i]];
    			B[fa[a[i]]]+=B[a[i]];
    			C[fa[a[i]]]+=C[a[i]];
    		}
    		for(int i=2;i<=tot;i++){
    			LL x=1ll*A[i]*B[i]%mod*C[i]%mod;
    			ans[len[fa[i]]+1]+=x;
    			ans[len[i]+1]-=x;
    		}
    		for(int i=1;i<=n;i++) ans[i]=((ans[i-1]+ans[i])%mod+mod)%mod;
    		for(int i=1;i<=n;i++) printf("%lld ",ans[i]);
    	}
    }sam;
    
    
    int main(){
    	scanf("%s",s+1),slen=strlen(s+1);
    	sam.insert(A);n=min(slen,n);
    	scanf("%s",s+1),slen=strlen(s+1);
    	sam.insert(B);n=min(slen,n);
    	scanf("%s",s+1),slen=strlen(s+1);
    	sam.insert(C);n=min(slen,n);
    	sam.solve();
    	return 0;
    }
    

    到这里,我后缀自动机的刷题基本结束了,虽然题单上还有很多难题没有刷,但那些都是结合了其他算法的题,对于 SAM 和广义 SAM 的原理和性质有了一些基本的了解就是这几天的主要任务了,也熟练的掌握了写法,效果还不错。之后也会慢慢把那些难题补完的。
    下一步计划学习线段树合并。

  • 相关阅读:
    java语法基础
    向linux内核增加一个系统调用-1
    dp-矩阵连乘
    struct和typedef struct
    Ubuntu安装Chrome及hosts修改
    c++primer-p100.用迭代器进行二分法搜索
    c++primer-p101.ex3.24
    c++ vector用法和迭代器
    Bytes和bits的区别(字节和位的区别)
    基于R语言的数据分析和挖掘方法总结——中位数检验
  • 原文地址:https://www.cnblogs.com/BakaCirno/p/12670860.html
Copyright © 2020-2023  润新知