BZOJ3790:神奇项链

博客详细介绍了如何运用Manacher算法解决神奇项链问题,即构建回文串并求最少拼接次数。通过将每个字符串位置视为线段,将问题转化为线段覆盖问题,并采用贪心策略(堆)进行求解。
摘要由CSDN通过智能技术生成

Manacher 贪心

题目传送门

题目大意: 给你一个字符串,你可以造任意的回文串并把它们拼起来得到原串,求最少拼接次数(回文串可重叠)。

先Manacher求出 p p p数组,把每个点看成一个一条线段,左右端点分别为 i − p [ i ] i-p[i] ip[i] i + p [ i ] i+p[i] i+p[i]。然后就变成线段覆盖问题(用最少的线段覆盖住整个区间),贪心即可(我懒就用了堆)。

代码:

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
#define F inline
using namespace std;
struct node{ int l,r; };
int id,r,ans,p[N]; char s[N],s1[N];
F bool operator < (node a,node b){ return a.l>b.l; }
priority_queue <node> q;
int main(){
	while (scanf("%s",s)!=EOF){
		memset(s1,0,sizeof(s1)),s1[0]='$';
		for (int i=0;s[i];i++) s1[2*i+1]='#',s1[2*i+2]=s[i];
		s1[strlen(s1)]='#',memset(p,0,sizeof(p)),id=r=ans=0;
		for (int i=1;s1[i];i++){
			p[i]=r>i?min(p[id*2-i],r-i):1;
			while (s1[i+p[i]]==s1[i-p[i]]) p[i]++;
			if (p[i]+i>r) r=p[i]+i,id=i;
		}
		while (!q.empty()) q.pop(); int len=strlen(s1)-1;
		for (int i=2;i<len;i++) q.push((node){i-p[i]+1,i+p[i]-1});
		for (int lst=1,now=0;lst<len;ans++,lst=now)
			while (!q.empty()&&q.top().l<=lst) now=max(now,q.top().r),q.pop();
		printf("%d\n",ans-1);
	}
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值