zoukankan      html  css  js  c++  java
  • luoguP3181 [HAOI2016]找相同字符

    题意

    考虑将(s1)(s2)接在一起求出相同子串个数,再求出(s1)自己匹配的相同子串个数和(s2)自己匹配的相同子串个数减去即可。

    如何求相同子串个数:
    我们知道子串的集合即所有后缀的前缀集合,于是实际上答案就是:
    (sumlimits_{i=1}^nsumlimits_{j=i+1}^nlcp(sa_i,sa_j))

    接下来就和这题相同了。

    code:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn=400010;
    int n,m,num,top;
    int sa[maxn],rk[maxn],oldrk[maxn],id[maxn],tmpid[maxn],cnt[maxn],height[maxn],L[maxn],R[maxn],sta[maxn];
    ll ans;
    char s1[maxn],s2[maxn],s[maxn];
    inline bool check(int x,int y,int k){return oldrk[x]==oldrk[y]&&oldrk[x+k]==oldrk[y+k];}
    inline void get_sa(char* s,int len)
    {
    	memset(cnt,0,sizeof(cnt));
    	num=300;
    	for(int i=1;i<=len;i++)cnt[rk[i]=s[i]]++;
    	for(int i=1;i<=num;i++)cnt[i]+=cnt[i-1];
    	for(int i=len;i;i--)sa[cnt[rk[i]]--]=i;
    	for(int t=1;t<=len;t<<=1)
    	{
    		int tot=0;
    		for(int i=len-t+1;i<=len;i++)id[++tot]=i;
    		for(int i=1;i<=len;i++)if(sa[i]>t)id[++tot]=sa[i]-t;
    		tot=0;
    		memset(cnt,0,sizeof(cnt));
    		for(int i=1;i<=len;i++)cnt[tmpid[i]=rk[id[i]]]++;
    		for(int i=1;i<=num;i++)cnt[i]+=cnt[i-1];
    		for(int i=len;i;i--)sa[cnt[tmpid[i]]--]=id[i];
    		memcpy(oldrk,rk,sizeof(rk));
    		for(int i=1;i<=len;i++)rk[sa[i]]=check(sa[i-1],sa[i],t)?tot:++tot;
    		num=tot;
    		if(num==len)break;
    	}
    	for(int i=1,j=0;i<=len;i++)
    	{
    		if(j)j--;
    		while(s[i+j]==s[sa[rk[i]-1]+j])j++;
    		height[rk[i]]=j;
    	}
    }
    inline ll calc(int len)
    {
    	ll res=0;
    	sta[top=1]=1;
    	for(int i=2;i<=len;i++)
    	{
    		while(top&&height[sta[top]]>=height[i])R[sta[top--]]=i;
    		L[i]=sta[top];sta[++top]=i;
    	}
    	while(top)R[sta[top--]]=len+1;
    	for(int i=2;i<=len;i++)res+=1ll*height[i]*(R[i]-i)*(i-L[i]);
    	return res;
    }
    int main()
    {
    	scanf("%s%s",s1+1,s2+1);
    	n=strlen(s1+1),m=strlen(s2+1);
    	get_sa(s1,n);ans-=calc(n);
    	get_sa(s2,m);ans-=calc(m);
    	for(int i=1;i<=n;i++)s[i]=s1[i];
    	s[n+1]='#';
    	for(int i=1;i<=m;i++)s[n+i+1]=s2[i];
    	get_sa(s,n+m+1);ans+=calc(n+m+1);
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    Quick Sort
    Binary Search
    trollcave解题
    Openvas简介
    SMB扫描-Server Message Block 协议、nmap
    漏洞基本概念
    防火墙识别、负载均衡识别、waf识别
    Centos7下部署Python项目
    Python-Redis数据类型操作
    MySQL的事务隔离级别
  • 原文地址:https://www.cnblogs.com/nofind/p/12052951.html
Copyright © 2011-2022 走看看