• 洛谷 P2463 [SDOI2008]Sandy的卡片【后缀数组】


    传送门
    这个题就是求 (n) 个差分数列的最长公共子串,为啥是差分数列呢,因为如果一个串都加一个数会变成另一个串,那么这两个串的差分数列除了第一项都相等。
    所以把 (n) 个串的差分数列除去第一项后用不同的数间隔然后拼起来,对应位置打上标记记录属于哪个串,然后求后缀数组。
    那么如何求 (n) 个串的最长公共子串呢,可以用尺取法求出哪些区间里包含了 (n) 个不同的标记,然后求这些区间的 lcp 就行了。

    #include <bits/stdc++.h>
    using namespace std;
    const int N=2e6+10;
    int T,n,s[N],sa[N*2],rk[N*2],tp[N*2],ht[N],m,a[N],id[N],c[N];
    int ins[N],cnt,st[N][22];
    
    void getsa(){
    	m=5000;
    	for(int i=1;i<=n;i++) c[rk[i]=s[i]]++;
    	for(int i=1;i<=m;i++) c[i]+=c[i-1];
    	for(int i=n;i>=1;i--) sa[c[rk[i]]--]=i;
    	for(int w=1,p=0;p<n;w<<=1,m=p){
    		p=0;
    		for(int i=n-w+1;i<=n;i++) tp[++p]=i;
    		for(int i=1;i<=n;i++) if(sa[i]>w) tp[++p]=sa[i]-w;
    		for(int i=1;i<=m;i++) c[i]=0;
    		for(int i=1;i<=n;i++) c[rk[i]]++;
    		for(int i=1;i<=m;i++) c[i]+=c[i-1];
    		for(int i=n;i>=1;i--) sa[c[rk[tp[i]]]--]=tp[i];
    		swap(tp,rk);
    		rk[sa[1]]=p=1;
    		for(int i=2;i<=n;i++)
    			rk[sa[i]]=(tp[sa[i]]>tp[sa[i-1]]||tp[sa[i]+w]>tp[sa[i-1]+w])?++p:p;
    	}
    	int k=0;
    	for(int i=1;i<=n;i++){
    		if(k) k--;
    		int j=sa[rk[i]-1];
    		while(s[i+k]==s[j+k]) ++k;
    		ht[rk[i]]=st[rk[i]][0]=k;
    	}
    	for(int i=1;(1<<i)<=n;i++)
    		for(int j=n;j>(1<<i);j--)
    			st[j][i]=min(st[j][i-1],st[j-(1<<i-1)][i-1]);
    }
    
    void add(int x){
    	ins[id[x]]++;
    	cnt+=(ins[id[x]]==1);
    }
    
    int lcp(int x,int y){
    	int rkx=rk[x],rky=rk[y];
    	if(rkx>rky) swap(rkx,rky);
    	int p=log2(rky-rkx);
    	return min(st[rky][p],st[rkx+(1<<p)][p]);
    }
    
    int main(){
    	scanf("%d",&T);
    	for(int w=1,len;w<=T;w++){
    		scanf("%d",&len);
    		for(int i=1;i<=len;i++) scanf("%d",&a[i]);
    		for(int i=len;i>=1;i--) a[i]-=a[i-1],a[i]+=2000;
    		s[++n]=w+4000;
    		for(int i=2;i<=len;i++) s[++n]=a[i],id[n]=w;
    	}
    	getsa();
    	int ans=0;
    	for(int L=1,R=0;R<=n;L++){
    		while(R<n&&cnt<T) add(sa[++R]);
    		if(cnt<T&&!id[sa[R+1]]) break;
    		ans=max(ans,lcp(sa[L],sa[R]));
    		ins[id[sa[L]]]--;
    		cnt-=(ins[id[sa[L]]]==0);
    	}
    	printf("%d
    ",ans+1);
    	return 0;
    }
    
  • 相关阅读:
    UNIX网络编程——TCP/IP简介
    UNIX环境高级编程——TCP/IP网络编程
    UNIX环境高级编程——网络编程常用函数及结构
    UNIX环境高级编程——网络基础概念
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
  • 原文地址:https://www.cnblogs.com/BakaCirno/p/12698777.html
Copyright © 2020-2023  润新知