• [HAOI2016]找相同字符(广义SAM)


    [HAOI2016]找相同字符(广义SAM)

    题面

    给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数。两个方案不同当且仅当这两个子串中有一个位置不同。

    分析

    此题有一个比较繁琐的后缀数组做法,但是用广义SAM可以秒杀。

    把两个串建成广义SAM,对于每个后缀,记录(endpos)集合中落在第一个串中和第二个串中的位置个数,记为(cnt_{x,0},cnt_{x,1})
    对于自动机上的每个节点(x),出现位置方案数的贡献是(cnt_{x,0} cdot cnt_{x,1}),注意这个节点代表了一系列不同子串,还要乘上这个位置代表的本质不同子串个数(len(x)-len(link(x)))

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #define maxn 200000 
    #define maxc 26 
    using namespace std;
    typedef long long ll;
    int n,m;
    char s[maxn+5],t[maxn+5]; 
    struct SAM{
    #define len(x) (t[x].len)
    #define link(x) (t[x].link)
    	struct node{
    		int len;
    		int link;
    		int ch[maxc+1];
    		int cnt[2];
    	}t[maxn*4+5];
    	const int root=1;
    	int ptr=1,last=root;
    	void extend(int c,int type){
    		 int p=last,cur=++ptr;
    		 len(cur)=len(p)+1;
    		 if(type<=1) t[cur].cnt[type]++;
    		 while(p&&!t[p].ch[c]){
    		 	t[p].ch[c]=cur;
    		 	p=link(p);
    		 }
    		 if(p==0) link(cur)=root;
    		 else{
    		 	int q=t[p].ch[c];
    		 	if(len(p)+1==len(q)) link(cur)=q;
    		 	else{
    		 		int clo=++ptr;
    		 		link(clo)=link(q);
    		 		len(clo)=len(p)+1;
    		 		for(int i=0;i<=maxc;i++) t[clo].ch[i]=t[q].ch[i];
    		 		link(q)=link(cur)=clo;
    		 		while(p&&t[p].ch[c]==q){
    		 			t[p].ch[c]=clo;
    		 			p=link(p);
    				 }
    			 }
    		 }
    		 last=cur;
    	}
    	void topo_sort(){
    		static int in[maxn*4+5];
    		queue<int>q;
    		for(int i=2;i<=ptr;i++) in[link(i)]++;
    		for(int i=2;i<=ptr;i++) if(!in[i]) q.push(i);
    		while(!q.empty()){
    			int x=q.front();
    			q.pop();
    			in[link(x)]--;
    			for(int i=0;i<=1;i++) t[link(x)].cnt[i]+=t[x].cnt[i];
    			if(in[link(x)]==0) q.push(link(x));
    		}
    	}
    	ll calc(){
    		ll ans=0;
    		for(int i=2;i<=ptr;i++) ans+=1ll*(t[i].len-t[link(i)].len)*t[i].cnt[0]*t[i].cnt[1]; 
    		return ans;
    	}
    }T;
    int main(){
    	scanf("%s",s+1);
    	scanf("%s",t+1);
    	n=strlen(s+1),m=strlen(t+1);
    	for(int i=1;i<=n;i++) T.extend(s[i]-'a',0);
    //	T.extend(26,2);
    	T.last=T.root;
    	for(int i=1;i<=m;i++) T.extend(t[i]-'a',1);
    	T.topo_sort();
    	printf("%lld
    ",T.calc());
    }
    
  • 相关阅读:
    Hadoop整理二(Hadoop分布式存储系统HDFS)
    Hadoop整理一(初识Hadoop)
    Unalignable boolean Series provided as indexer (index of the boolean Series and of the indexed object do not match
    Oracle登录
    神经网络一(用tensorflow搭建简单的神经网络并可视化)
    Qt程序启动画面播放(gif与swf两种动画格式)
    VS2008+GDI实现多幅图像的GIF动画制作
    C++读取特定路径下文件目录及文件名称
    求助——数据处理问题
    VC6.0读取Excel文件数据
  • 原文地址:https://www.cnblogs.com/birchtree/p/12628351.html
Copyright © 2020-2023  润新知