zoukankan      html  css  js  c++  java
  • AcWing 2766. 后缀自动机

    后缀数组解法

    前置题目

    Solution

    一个字符串的后缀的所有前缀恰好不重不漏地覆盖了所有的子串,所以我们可以考虑用后缀数组来做。

    比如:babab
    排完序后

    1. ab
    2. abab
    3. b
    4. bab
    5. babab

    (以下后缀均指排名为 (i) 的后缀,而不是原串的第 (i) 个后缀)
    一个后缀 (i) 的一个长度为 (len) 的前缀的出现次数是 使 (lcp(i,j) geq len) 成立的 (j) 最大值与最小值之差+1.
    在后缀数组中,我们有 (lcp(i,j)=min(lcp(i,i+1),...,lcp(j-1,j)),i<j)
    因此 (lcp(i,j) leq lcp(i,i+1),...,lcp(j-1,j))
    因此只需要在 height[] 求出左边和右边 height[] 小于 height[i] 的第一个 j,即为使 (lcp(i,j) geq len) 的成立的 (j) 最小值-1与最大值+1,同时之后的 (j) 一定不能使 (lcp(i,j) geq len) 成立。
    还要乘一个子串长度:把子串长度看作高,把 (|jmax-jmin|) 看作宽。
    由此可以抽象为 131. 直方图中最大的矩形 来写。

    Code

    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<ctime>
    #include<cmath>
    #include<bitset>
    #include<vector>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    
    const int N=1e6+5;
    
    int n,m;
    char s[N];
    int sa[N],rk[N],ht[N];
    // sa[i] 表示排名为i的后缀是 sa[i] 
    void get_sa()
    {
    	static int x[N],y[N],c[N];
    	int i,k,num;
    	memset(c,0,sizeof c);
    	for(i=1;i<=n;i++) c[x[i]=s[i]]++;
    	for(i=1;i<=m;i++) c[i]+=c[i-1];
    	for(i=n;i>=1;i--) sa[c[x[i]]--]=i;
    	
    	for(k=1;k<=n;k<<=1) {
    		num=0;
    		for(i=n-k+1;i<=n;i++) y[++num]=i;
    		for(i=1;i<=n;i++) 
    			if(sa[i]>k) y[++num]=sa[i]-k;
    		
    		for(i=1;i<=m;i++) c[i]=0;
    		for(i=1;i<=n;i++) c[x[i]]++;
    		for(i=1;i<=m;i++) c[i]+=c[i-1];
    		for(i=n;i>=1;i--) sa[c[x[y[i]]]--]=y[i],y[i]=0;
    		
    		swap(x,y);
    		x[sa[1]]=1,num=1;
    		for(i=2;i<=n;i++) 
    			x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]) ? num : ++num;
    		if(num==n) break;
    		m=num;
    	} 
    	for(i=1;i<=n;i++) rk[sa[i]]=i;
    //	for(i=1;i<=n;i++) printf("%d ",sa[i]);
    //	printf("
    ");
    }
    
    void get_ht()
    {
    	int i,j,k=0;
    	// dim h[i]=height[rk[i]]
    	// h[i] >= h[i-1]-1;
    	for(i=1;i<=n;i++) {
    		if(rk[i]==1) continue;
    		if(k) k--;
    		j=sa[rk[i]-1];
    		while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k]) k++;
    		ht[rk[i]]=k; 
    	}
    //	for(i=1;i<=n;i++) printf("%d ",ht[i]);
    //	printf("
    ");	
    }
    
    int pl[N],pr[N]; // ht[] 左边和右边第一个更小的数。 
    
    void calc(int a[],int p[])
    {
    	static int stk[N],top;
    	memset(stk,0,sizeof stk);
    	top=0,stk[top]=1;
    
    	for(int i=2;i<=n;i++) {
    		while(top>=0&&a[stk[top]]>=a[i]) top--;
    		p[i]=stk[top];
    		stk[++top]=i;
    	}
    }
    LL ans;
    
    int main()
    {
    //	freopen("1.in","r",stdin);
    	int i;
    	scanf("%s",s+1);
    	n=strlen(s+1),m=122;
    	get_sa(),get_ht();
    	
    	calc(ht,pl);
    	reverse(ht+2,ht+n+1);
    	calc(ht,pr);
    	reverse(ht+2,ht+n+1);
    	reverse(pr+2,pr+n+1);
    	for(i=2;i<=n;i++) pr[i]=n+2-pr[i];
    //	for(i=1;i<=n;i++) printf("%d ",pr[i]);
    //	printf("
    ");	
    	for(i=2;i<=n;i++) {
    		if(pr[i]-pl[i]<=1) continue;
    		ans=max(ans,(LL)(pr[i]-pl[i])*(LL)ht[i]);
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    如何阅读修改代码
    C C++ TDD单元测试非常好的书
    应用代理 socket TCP协议 的资料
    闲聊桌面应用开发[Win16->Win32->ATL/WTL/MFC->WinForm->WPF/Silverlight/WinRT]
    MySQL sharding的几个参考地址
    ubuntu环境变量
    Angular JS | Closure | Google Web Toolkit | Dart | Polymer 概要汇集
    Linux下的应用程序性能分析 总结
    ubuntu处理中文时设置locale
    Tomcat https自制证书和浏览器配置
  • 原文地址:https://www.cnblogs.com/cjl-world/p/14054075.html
Copyright © 2011-2022 走看看