zoukankan      html  css  js  c++  java
  • ●BZOJ 4566 [Haoi2016]找相同字符

    题链:

    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
    ",SUF.Count(S,T));
    	return 0;
    }
    

      

  • 相关阅读:
    C#心得与经验(二)
    C#心得与经验(一)
    与C#的第一次~
    2014应届生面试经验详谈。
    Block基本用法
    OC中得那些“点”
    PCH文件的使用
    UIScrollView的subViews使用小注意
    分享一下本人录制图像处理与OpenCV学习视频
    OpenCV 3.2正式发布啦
  • 原文地址:https://www.cnblogs.com/zj75211/p/8541864.html
Copyright © 2011-2022 走看看