zoukankan      html  css  js  c++  java
  • 【后缀数组】【线段树】poj3974 Palindrome

    考虑奇数长度的回文,对于字符串上的每个位置i,如果知道从i开始的后缀和到i为止的前缀反转后的字符串的lcp长度的话,也就知道了以第i个字符为对称中心的最长回文的长度了。因此,我们用在S中不会出现的字符将S和S反转后的字符串拼接起来,得到字符串S',计算S'的sa。于是,从i开始的后缀和到i为止的前缀反转后的字符串就都是S'中的后缀了,利用高度数组,可以轻易地求得它们最长公共前缀的长度。

    对于长度为偶数的回文的处理也基本相同。

    哈哈哈,MLE+TLE不可避。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    #define N 2000001
    #define INF 2147483647
    char s[N];
    int tong['z'+1],t[N],n,t2[N],sa[N],lcp[N],rank[N];
    bool cmp(int *y,int i,int k)
    {
    	return ((y[sa[i-1]]==y[sa[i]])&&((sa[i-1]+k>=n?-1:y[sa[i-1]+k])==(sa[i]+k>=n?-1:y[sa[i]+k])));
    }
    void build_sa(int range)
    {
    	int *x=t,*y=t2;
    	memset(tong,0,sizeof(int)*range);
    	for(int i=0;i<n;++i) tong[x[i]=s[i]]++;
    	for(int i=1;i<range;++i) tong[i]+=tong[i-1];
    	for(int i=n-1;i>=0;--i) sa[--tong[x[i]]]=i;
    	for(int k=1;k<=n;k<<=1)
    	  {
    	  	int p=0;
    	  	for(int i=n-k;i<n;++i) y[p++]=i;
    	  	for(int i=0;i<n;++i) if(sa[i]>=k) y[p++]=sa[i]-k;
    	  	memset(tong,0,sizeof(int)*range);
    		for(int i=0;i<n;++i) tong[x[y[i]]]++;
    		for(int i=1;i<range;++i) tong[i]+=tong[i-1];
    		for(int i=n-1;i>=0;--i) sa[--tong[x[y[i]]]]=y[i];
    	  	swap(x,y); p=1; x[sa[0]]=0;
    	  	for(int i=1;i<n;++i) x[sa[i]]=cmp(y,i,k)?p-1:p++;
    	  	if(p>=n) break;
    	  	range=p;
    	  }
    }
    void get_lcp()
    {
    	int k=0;
    	for(int i=0;i<n;++i) rank[sa[i]]=i;
    	for(int i=0;i<n;++i) if(rank[i])
    	  {
    	  	if(k) --k;
    	  	int j=sa[rank[i]-1];
    	  	while(s[i+k]==s[j+k]) ++k;
    	  	lcp[rank[i]]=k;
    	  }
    }
    int minv[N<<2];
    void buildtree(int rt,int l,int r)
    {
    	if(l==r)
    	  {
    	  	minv[rt]=lcp[l];
    	  	return;
    	  }
    	int m=(l+r>>1);
    	buildtree(rt<<1,l,m);
    	buildtree(rt<<1|1,m+1,r);
    	minv[rt]=min(minv[rt<<1],minv[rt<<1|1]);
    }
    int query(int ql,int qr,int rt,int l,int r)
    {
    	if(ql<=l&&r<=qr) return minv[rt];
    	int m=(l+r>>1),res=INF;
    	if(ql<=m) res=min(res,query(ql,qr,rt<<1,l,m));
    	if(m<qr) res=min(res,query(ql,qr,rt<<1|1,m+1,r));
    	return res;
    }
    int main()
    {
    	int T=0;
    	while(1)
    	  {
    	  	scanf("%s",s);
    	  	if(s[0]=='E') break;
    	  	++T;
    	  	int l=strlen(s);
    	  	n=(l<<1|1);
    	  	s[l]='$';
    	  	reverse_copy(s,s+l,s+l+1);
    	  	build_sa('z'+1);
    	  	get_lcp();
    	  	buildtree(1,1,n-1);
    	  	int ans=0;
    	  	for(int i=0;i<l;++i)//奇数长度回文
    	  	  ans=max(ans,(query(min(rank[i],rank[n-i-1])+1,
    		  max(rank[i],rank[n-i-1]),1,1,n-1)<<1)-1);
    		for(int i=1;i<l;++i)//偶数数长度回文
    	  	  ans=max(ans,(query(min(rank[i],rank[n-i])+1,
    		  max(rank[i],rank[n-i]),1,1,n-1)<<1));
    		printf("Case %d: %d
    ",T,ans);
    	  }
    	return 0;
    }
  • 相关阅读:
    关于Java中String类的hashCode方法
    重写equal()时为什么也得重写hashCode()之深度解读equal方法与hashCode方法渊源
    vue+eslint+prettier+vetur 使用vscode 前端工程化
    vue webpack 打包优化
    移动端兼容
    vue 跨域使用
    vue2.0性能优化
    前端 mock的使用
    vue 使用Lodash 的throttle(节流)与debounce(防抖
    webpack4 安装及使用
  • 原文地址:https://www.cnblogs.com/autsky-jadek/p/4460650.html
Copyright © 2011-2022 走看看