zoukankan      html  css  js  c++  java
  • BZOJ.4566.[HAOI2016]找相同字符(后缀自动机)

    题目链接

    SA+单调栈做法见这儿
    做这种题终于不用写SA+二分/set/单调栈...了。。

    (Description)

    给定两个字符串,求它们有多少个相同子串。相同串的位置不同算多个。

    (Solution)

    对一个串建SAM。因为要统计不同位置个数,所以匹配一个点的贡献为((val[i]=(len[i]-len[fa[i]])*|right[i]|)+val[fa[i]]+val[fa[fa[i]]]...)
    然后另一个串在SAM上走。维护当前已匹配的长度l,则当前贡献为(val[fa[i]]+(l-len[fa[i]])*|right[i]|)

    //52776kb	1500ms
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define gc() getchar()
    typedef long long LL;
    const int N=4e5+5;
    
    struct Suffix_Automaton
    {
    	int las,tot,fa[N],son[N][26],len[N],A[N],tm[N],right[N];
    	LL val[N];
    	char s[N];
    
    	void Insert(int c)
    	{
    		int np=++tot,p=las;
    		len[las=np]=len[p]+1, right[np]=1;
    		for(; p&&!son[p][c]; p=fa[p]) son[p][c]=np;
    		if(!p) fa[np]=1;
    		else
    		{
    			int q=son[p][c];
    			if(len[q]==len[p]+1) fa[np]=q;
    			else
    			{
    				int nq=++tot; len[nq]=len[p]+1;
    				memcpy(son[nq],son[q],sizeof son[q]);
    				fa[nq]=fa[q], fa[q]=fa[np]=nq;
    				for(; son[p][c]==q; p=fa[p]) son[p][c]=nq;
    			}
    		}
    	}
    	void Build()
    	{
    		las=tot=1;
    		scanf("%s",s); int l=strlen(s);
    		for(int i=0; i<l; ++i) Insert(s[i]-'a');
    		for(int i=1; i<=tot; ++i) ++tm[len[i]];
    		for(int i=1; i<=l; ++i) tm[i]+=tm[i-1];
    		for(int i=1; i<=tot; ++i) A[tm[len[i]]--]=i;
    
    		for(int i=tot,x=A[i]; i; x=A[--i]) right[fa[x]]+=right[x];
    		for(int i=1; i<=tot; ++i) val[i]=1ll*(len[i]-len[fa[i]])*right[i];
    		for(int i=2,x=A[2]; i<=tot; x=A[++i]) val[x]+=val[fa[x]];
    	}
    	void Query()
    	{
    		scanf("%s",s);
    		LL ans=0;
    		for(int p=1,now=0,c,i=0,l=strlen(s); i<l; ++i)
    		{
    			if(son[p][c=s[i]-'a']) ++now, p=son[p][c];
    			else
    			{
    				for(; p&&!son[p][c]; p=fa[p]);
    				if(!p) p=1, now=0;
    				else now=len[p]+1, p=son[p][c];
    			}
    			ans+=val[fa[p]]+1ll*(now-len[fa[p]])*right[p];
    		}
    		printf("%lld",ans);
    	}
    }sam;
    
    int main()
    {
    	sam.Build(), sam.Query();
    	return 0;
    }
    
  • 相关阅读:
    判断以下字符串中出现次数最多的字符,并且算出该字符出现的次数
    status的状态码
    call和apply的区别?
    闭包
    $(document).ready和window. onload的区别
    python_pandas常用操作
    python经典例题
    爬B站并保存成csv文件。提供数据
    data_analysis:初识numpy
    01爬取豆瓣网电影数据进行numpy的练习
  • 原文地址:https://www.cnblogs.com/SovietPower/p/9241813.html
Copyright © 2011-2022 走看看