• POJ2774 Long Long Message


    蒟蒻的第一道后缀数组的题目!!(update:现在也有SAM版本的啦!!)

    SA是个好东西,本题就是考察它的经典应用——求一个字符串里面两个后缀的最长公共前缀!

    所以我们就可以考虑把两个字符串拼起来,然后查找两个后缀,使得他们的最长公共前缀最长。

    然后就是板子了吧qwqwq(感觉SA的写法和网上很多人的不一样??不过原理还是一样的啦qwq)

    不会SA的可以参考自为风月马前卒大佬的blog,讲的真的很详细:戳我

    需要注意的一点就是最后查询的时候一定要保证两个后缀的起始位置下标不能在同一个子串里,怎么处理呢?一个简单的方法是构建字符串的时候就在两个字符串中间加入一个根本就不会出现的字符。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define MAXN 300010
    using namespace std;
    int len1,len2,n,ans,m;
    int tag[MAXN],h[MAXN],tax[MAXN],s[MAXN],rnk[MAXN],tp[MAXN],sa[MAXN];
    char s1[MAXN],s2[MAXN];
    inline void qsort()
    {
    	for(int i=1;i<=m;i++) tax[i]=0;
    	for(int i=1;i<=n;i++) tax[rnk[i]]++;
    	for(int i=1;i<=m;i++) tax[i]+=tax[i-1];
    	for(int i=n;i>=1;i--) sa[tax[rnk[tp[i]]]--]=tp[i];
    }
    inline void suffixsort()
    {
    	m=75;
    	for(int i=1;i<=n;i++) rnk[i]=s[i],tp[i]=i;
    	qsort();
    	for(int w=1,p=0;p<n;m=p,w<<=1)
    	{
    		p=0;
    		for(int i=1;i<=w;i++) tp[++p]=n-w+i;
    		for(int i=1;i<=n;i++) if(sa[i]>w) tp[++p]=sa[i]-w;
    		qsort();
    		swap(tp,rnk);
    		rnk[sa[1]]=p=1;
    		for(int i=2;i<=n;i++) rnk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]])&&(tp[sa[i]+w]==tp[sa[i-1]+w])?p:++p;
    	}
    }
    inline void get_h()
    {
    	int hi=0,j;
    	for(int i=1;i<=n;i++)
    	{
    		j=sa[rnk[i]-1];
    		if(hi>0) hi--;
    		for(;j+hi<=n&&i+hi<=n;hi++)
    			if(s[i+hi]!=s[j+hi]) break;
    		h[rnk[i]-1]=hi;
    	}
    }
    int main()
    {
    	#ifndef ONLINE_JUDGE
    	freopen("ce.in","r",stdin);
    	#endif
    	scanf("%s",s1+1),scanf("%s",s2+1);
    	len1=strlen(s1+1),len2=strlen(s2+1);
    	n=len1+len2+1;
    	for(int i=1;i<=len1;i++) s[i]=s1[i]-'a'+1;
    	s[len1+1]=30;
    	for(int i=1;i<=len2;i++) s[i+len1+1]=s2[i]-'a'+1;
    	suffixsort();
    	get_h();
    	for(int i=1;i<n;i++) 
    		if((sa[i]<=len1)!=(sa[i+1]<=len1))
    			ans=max(ans,h[i]);
    	printf("%d
    ",ans);
    	return 0;
    }
    

    SAM怎么做?

    其实就是对其中一个建立后缀自动机,然后另外一个在上面匹配。

    从根节点1开始,如果当前节点存在,可以匹配,那么cnt++。

    如果当前节点不存在,那么往上面跳parent,直到可以匹配,那时候cnt=t[now].longest+1即可

    如果一跳直接跳到了1节点,相当于接上了一个空串,即没有和任何数进行匹配,cnt=0。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define MAXN 255000
    #define ch b
    using namespace std;
    int T,tot,last,ans;
    char a[MAXN],b[MAXN];
    struct Node{int son[26],ff,len;}t[MAXN<<2];
    inline void extend(int c)
    {
    	int p=last,np=++tot;last=np;
    	t[np].len=t[p].len+1;
    	while(p&&!t[p].son[c]) t[p].son[c]=np,p=t[p].ff;
    	if(!p) t[np].ff=1;
    	else 
    	{
    		int q=t[p].son[c];
    		if(t[q].len==t[p].len+1) t[np].ff=q;
    		else
    		{
    			int nq=++tot;
    			t[nq]=t[q];t[nq].len=t[p].len+1;
    			t[q].ff=t[np].ff=nq;
    			while(p&&t[p].son[c]==q) t[p].son[c]=nq,p=t[p].ff;
    		}
    	}
    }
    int main()
    {
    	#ifndef ONLINE_JUDGE
    	freopen("ce.in","r",stdin);
    	#endif
    	scanf("%s%s",a+1,b+1);
    	int lena=strlen(a+1),lenb=strlen(b+1);
    //	printf("lena=%d lenb=%d
    ",lena,lenb);
    	tot=last=1;
    	for(int i=1;i<=lena;i++) extend(a[i]-'a');
    	int now=1,cur_ans=0;
    	for(int i=1;i<=lenb;i++)
    	{
    		if(t[now].son[b[i]-'a'])
    		{
    			cur_ans++;
    			now=t[now].son[b[i]-'a'];
    		}
    		else
    		{
    			while(now&&!t[now].son[b[i]-'a']) now=t[now].ff;
    			if(!now) cur_ans=0,now=1;
    			else cur_ans=t[now].len+1,now=t[now].son[b[i]-'a'];
    		}
    //		printf("i=%d cur_ans=%d
    ",i,cur_ans);
    		ans=max(ans,cur_ans);
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    qt.network.ssl: QSslSocket: cannot call unresolved function SSLv23_client_method
    使用 acl_cpp 的 HttpServlet 类及服务器框架编写WEB服务器程序(系列文章)
    C编译器剖析PDF文档及UCC编译器162.3
    深入浅出NodeJS——数据通信,NET模块运行机制
    看AngularJS
    如何编写高效的jQuery代码
    Express安装入门与模版引擎ejs
    使用SeaJS实现模块化JavaScript开发
    RequireJS 入门指南
    RequireJS
  • 原文地址:https://www.cnblogs.com/fengxunling/p/10235820.html
Copyright © 2020-2023  润新知