码迷,mamicode.com
首页 > 其他好文 > 详细

●BZOJ 4566 [Haoi2016]找相同字符

时间:2018-03-10 21:56:41      阅读:159      评论:0      收藏:0      [点我收藏+]

标签:efi   字符   sam   UI   define   char   统计   lin   line   

题链:

http://www.lydsy.com/JudgeOnline/problem.php?id=4566
题解:

广义后缀自动机
对两个串同时建立一个广义后缀自动机。
同时统计出每个状态对两个串分别的right集合大小right[*][0/1]
那么答案就是$$ANS=\sum_s right[s][0]×right[s][1]×(maxs[s]-maxs[parent[s]])$$


代码:

 

#include<bits/stdc++.h>
#define MAXN 200005
#define ll long long
using namespace std;
struct SAM{
	int size;
	int maxs[MAXN*6],trans[MAXN*6][26],parent[MAXN*6],right[MAXN*6][2];
	SAM(){
		memset(trans[0],0,sizeof(trans[0]));
		size=0; Newnode(0,0);
	}
	int Newnode(int a,int b){
		++size; maxs[size]=a;
		memcpy(trans[size],trans[b],sizeof(trans[b]));
		return size;
	}
	int Extend(int last,int x){
		static int p,np,q,nq; p=last;
		if(trans[p][x]&&maxs[p]+1==maxs[trans[p][x]]) return trans[p][x];
		np=Newnode(maxs[p]+1,0);
		for(;p&&!trans[p][x];p=parent[p]) trans[p][x]=np;
		if(!p) parent[np]=1;
		else{
			q=trans[p][x];
			if(maxs[p]+1!=maxs[q]){
				nq=Newnode(maxs[p]+1,q);
				parent[nq]=parent[q];
				parent[q]=parent[np]=nq;
				for(;p&&trans[p][x]==q;p=parent[p]) trans[p][x]=nq;
			}
			else parent[np]=q;
		}
		return np;
	}
	void Build(char *S){
		static int last; last=1;
		for(int i=0;S[i];i++) last=Extend(last,S[i]-‘a‘);
	}
	ll Count(char *S,char *T,ll ans=0){
		static int p,len,tmp[MAXN],order[MAXN*6];
		len=max(strlen(S),strlen(T));
		p=1; for(int i=0;S[i];i++) p=trans[p][S[i]-‘a‘],right[p][0]++;
		p=1; for(int i=0;T[i];i++) p=trans[p][T[i]-‘a‘],right[p][1]++;
		for(int i=1;i<=size;i++) tmp[maxs[i]]++;
		for(int i=1;i<=len;i++) tmp[i]+=tmp[i-1];
		for(int i=1;i<=size;i++) order[tmp[maxs[i]]--]=i;
		//不同于单串的后缀自动机,因为存在父子关系但是maxs相同的状态,但是可以确定的是这种情况下,父亲标号一定大于儿子标号
		for(int i=size;i;i--){
			p=order[i];
			right[parent[p]][0]+=right[p][0];
			right[parent[p]][1]+=right[p][1];
		}
		for(int i=1;i<=size;i++)
			ans+=1ll*(maxs[i]-maxs[parent[i]])*right[i][0]*right[i][1];
		return ans;
	}
}SUF;
int main(){
	static char S[MAXN],T[MAXN];
	scanf("%s%s",S,T);
	SUF.Build(S); 
	SUF.Build(T);
	printf("%lld\n",SUF.Count(S,T));
	return 0;
}

 

  

 

●BZOJ 4566 [Haoi2016]找相同字符

标签:efi   字符   sam   UI   define   char   统计   lin   line   

原文地址:https://www.cnblogs.com/zj75211/p/8541864.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!