• [SDOI2008]Sandy的卡片


    [SDOI2008]Sandy的卡片

    题目大意:

    (n(nle1000))个长度为(m_i(m_ile100))的序列序列中每个元素(a)满足(0le ale 1864)。定义两个串(A)(B)是相似的当且仅当(|A|=|B|)(A_i-B_i)均相等。问所有序列的公共相似串最大长度。

    思路:

    对所有序列相邻数字作差,题目转化为最长公共子串问题。

    显然,对于原来只有两个序列的情况,这是一个经典的最长公共子串问题。将所有的序列接在一起,相邻序列加入一个特殊点(infty)。对合并以后的序列构建后缀数组,即可通过(lcp)数组求解。

    对于有多个序列的情况,我们可以二分答案(k)。寻找(lcp)数组中是否有连续一段(ge k)且包含了所有的序列。

    时间复杂度(mathcal O(sum m_ilog^2sum m_i+log(min{m_i})nq))

    源代码:

    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<climits>
    #include<algorithm>
    inline int getint() {
    	register char ch;
    	while(!isdigit(ch=getchar()));
    	register int x=ch^'0';
    	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    	return x;
    }
    const int N=1e5+5000,Q=1001;
    int q,n,k,s[N],bel[N],sa[N],rank[N],lcp[N],tmp[N];
    bool flag[Q];
    inline bool cmp(const int &i,const int &j) {
    	if(rank[i]!=rank[j]) return rank[i]<rank[j];
    	const int ri=i+k<=n?rank[i+k]:-1;
    	const int rj=j+k<=n?rank[j+k]:-1;
    	return ri<rj;
    }
    inline void suffix_sort() {
    	for(register int i=0;i<=n;i++) {
    		sa[i]=i;
    		rank[i]=s[i];
    	}
    	for(k=1;k<=n;k<<=1) {
    		std::sort(&sa[0],&sa[n]+1,cmp);
    		tmp[sa[0]]=0;
    		for(register int i=1;i<=n;i++) {
    			tmp[sa[i]]=tmp[sa[i-1]]+!!cmp(sa[i-1],sa[i]);
    		}
    		std::copy(&tmp[0],&tmp[n]+1,rank);
    	}
    }
    inline void init_lcp() {
    	for(register int i=0,h=0;i<n;i++) {
    		if(h>0) h--;
    		const int &j=sa[rank[i]-1];
    		while(i+h<n&&j+h<n&&s[i+h]==s[j+h]) h++;
    		lcp[rank[i]-1]=h;
    	}
    }
    inline bool check(const int &k) {
    	for(register int i=0;i<=n;i++) {
    		if(lcp[i]<k) continue;
    		int j=i;
    		while(j<=n&&lcp[j]>=k) j++;
    		j--;
    		memset(flag,0,sizeof flag);
    		for(register int k=i;k<=j+1;k++) {
    			flag[bel[sa[k]]]=true;
    		}
    		i=j;
    		for(j=1;j<=q&&flag[j];j++);
    		if(j==q+1) return true;
    	}
    	return false;
    }
    int main() {
    	q=getint();
    	int l=0,r=INT_MAX;
    	for(register int t=1;t<=q;t++) {
    		const int m=getint();
    		r=std::min(r,m-1);
    		for(register int i=0;i<m;i++) {
    			s[n+i]=getint();
    		}
    		for(register int i=1;i<m;i++) {
    			s[n+i-1]-=s[n+i];
    			bel[n+i-1]=t;
    		}
    		s[n+m-1]=INT_MAX;
    		n+=m;
    	}
    	n--;
    	suffix_sort();
    	init_lcp();
    	while(l<=r) {
    		const int mid=(l+r)>>1;
    		if(check(mid)) {
    			l=mid+1;
    		} else {
    			r=mid-1;
    		}
    	}
    	printf("%d
    ",l);
    	return 0;
    }
    
  • 相关阅读:
    bzoj 3779 重组病毒——LCT维护子树信息
    bzoj 4010 [HNOI2015]菜肴制作——贪心
    bzoj 2535 && bzoj 2109 [Noi2010]Plane 航空管制——贪心
    bzoj 3671 [Noi2014]随机数生成器——贪心(时间复杂度分配)
    bzoj 2395 [Balkan 2011]Timeismoney——最小乘积生成树
    bzoj 3157 && bzoj 3516 国王奇遇记——推式子
    bzoj 1101 [POI2007]Zap——反演
    hdu 4372 Count the Buildings——第一类斯特林数
    bzoj 2406 矩阵——有源汇上下界可行流
    bzoj 2039 [2009国家集训队]employ人员雇佣——二元关系
  • 原文地址:https://www.cnblogs.com/skylee03/p/9174012.html
Copyright © 2020-2023  润新知