【后缀数组】【线段树】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\n",T,ans);
	  }
	return 0;
}

转载于:https://www.cnblogs.com/autsky-jadek/p/4460650.html

内容概要:本文系统介绍了算术优化算法(AOA)的基本原理、核心思想及Python实现方法,并通过图像分割的实际案例展示了其应用价值。AOA是一种基于种群的元启发式算法,其核心思想来源于四则运算,利用乘除运算进行全局勘探,加减运算进行局部开发,通过数学优化器加速函数(MOA)和数学优化概率(MOP)动态控制搜索过程,在全局探索与局部开发之间实现平衡。文章详细解析了算法的初始化、勘探与开发阶段的更新策略,并提供了完整的Python代码实现,结合Rastrigin函数进行测试验证。进一步地,以Flask框架搭建前后端分离系统,将AOA应用于图像分割任务,展示了其在实际工程中的可行性与高效性。最后,通过收敛速度、寻优精度等指标评估算法性能,并提出自适应参数调整、模型优化和并行计算等改进策略。; 适合人群:具备一定Python编程基础和优化算法基础知识的高校学生、科研人员及工程技术人员,尤其适合从事人工智能、图像处理、智能优化等领域的从业者;; 使用场景及目标:①理解元启发式算法的设计思想与实现机制;②掌握AOA在函数优化、图像分割等实际问题中的建模与求解方法;③学习如何将优化算法集成到Web系统中实现工程化应用;④为算法性能评估与改进提供实践参考; 阅读建议:建议读者结合代码逐行调试,深入理解算法流程中MOA与MOP的作用机制,尝试在不同测试函数上运行算法以观察性能差异,并可进一步扩展图像分割模块,引入更复杂的预处理或后处理技术以提升分割效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值