• BZOJ4566 HAOI2016找相同字符(后缀自动机)


      对第一个串建SAM,第二个串在上面跑,记录当前前缀匹配的最长后缀长度l,每次考虑当前前缀的贡献,对于当前所在节点显然是|right|*(l-len[fa]),而对于其parent树上所有祖先的贡献显然是|right|*(len-len[fa])。预处理一下就好了。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define N 400010
    char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
    int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
    int read()
    {
    	int x=0,f=1;char c=getchar();
    	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    	return x*f;
    }
    int n,m,cnt=1,last=1,son[N][26],fail[N],len[N],id[N],size[N],tot[N];
    ll ans,f[N],val[N];
    char a[N],b[N];
    void ins(int c)
    {
    	int x=++cnt,p=last;last=x;len[x]=len[p]+1;size[x]=1;
    	while (!son[p][c]) son[p][c]=x,p=fail[p];
    	if (!p) fail[x]=1;
    	else
    	{
    		int q=son[p][c];
    		if (len[p]+1==len[q]) fail[x]=q;
    		else
    		{
    			int y=++cnt;
    			len[y]=len[p]+1;
    			memcpy(son[y],son[q],sizeof(son[q]));
    			fail[y]=fail[q],fail[q]=fail[x]=y;
    			while (son[p][c]==q) son[p][c]=y,p=fail[p];
    		}
    	}
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("a.in","r",stdin);
    	freopen("a.out","w",stdout);
    	const char LL[]="%I64d
    ";
    #else
    	const char LL[]="%lld
    ";
    #endif
    	scanf("%s",a+1);n=strlen(a+1);
    	scanf("%s",b+1);m=strlen(b+1);
    	for (int i=1;i<=n;i++) ins(a[i]-'a');
    	for (int i=1;i<=cnt;i++) tot[len[i]]++;
    	for (int i=1;i<=n;i++) tot[i]+=tot[i-1];
    	for (int i=1;i<=cnt;i++) id[tot[len[i]]--]=i;
    	for (int i=cnt;i>=1;i--) size[fail[id[i]]]+=size[id[i]];
    	for (int i=1;i<=cnt;i++) val[id[i]]=val[fail[id[i]]]+1ll*size[id[i]]*(len[id[i]]-len[fail[id[i]]]);
    	int k=1,l=0;
    	for (int i=1;i<=m;i++)
    	{
    		while (!son[k][b[i]-'a']&&k) k=fail[k],l=len[k];
    		if (!k) k=1,l=0;
    		else l++,k=son[k][b[i]-'a'];
    		ans+=val[fail[k]]+1ll*size[k]*(l-len[fail[k]]);
    	}
    	cout<<ans;
    	return 0;
    }
    

      

  • 相关阅读:
    [题解]luogu_P1627_中位数(排列乱搞
    [题解]luogu_P3313_旅行(树剖
    [题解]luogu_P3201_梦幻布丁(启发式合并
    [题解]luogu_P4127_同类分布(数位dp
    [题解]弹飞绵羊
    [题解]luogu_P3469_BLO(理解tarjan/割点
    [题解]luogu_P3304直径(直径必经边
    [HAOI2015]树上操作(树链剖分)
    [SCOI2005]扫雷(递推)
    洛谷3865 ST表
  • 原文地址:https://www.cnblogs.com/Gloid/p/10807280.html
Copyright © 2020-2023  润新知