BZOJ 3790 Manacher 解题报告

本文介绍了一个有趣的算法问题——神奇项链,旨在寻找构造特定项链所需的最少回文串数量。通过Manacher算法确定每个子串的回文特性,并采用贪心策略进行优化。提供了完整的C++实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

3790: 神奇项链

Description

母亲节就要到了,小 H 准备送给她一个特殊的项链。这个项链可以看作一个用小写字
母组成的字符串,每个小写字母表示一种颜色。为了制作这个项链,小 H 购买了两个机器。第一个机器可以生成所有形式的回文串,第二个机器可以把两个回文串连接起来,而且第二个机器还有一个特殊的性质:假如一个字符串的后缀和一个字符串的前缀是完全相同的,那么可以将这个重复部分重叠。例如:aba和aca连接起来,可以生成串abaaca或 abaca。现在给出目标项链的样式,询问你需要使用第二个机器多少次才能生成这个特殊的项链。

Input

输入数据有多行,每行一个字符串,表示目标项链的样式。

Output

多行,每行一个答案表示最少需要使用第二个机器的次数。

Sample Input

abcdcba
abacada
abcdef

Sample Output

0
2
5

HINT

每个测试数据,输入不超过 5行
每行的字符串长度小于等于 50000

【解题报告】
题目:给出一个字符串(len<=10^5),求这个字符串最少由几个回文串拼接而成。注意拼接时可以把重复部分重叠起来,如: aba 和aca可以拼接成abaaca 或abaca。
于是再一次显而易见的Manacher过后,问题就变成了选择最少的区间覆盖整个区间的经典贪心。
不过除了贪心好像也可以用数据结构优化Dp来做

代码如下:

/**************************************************************
    Problem: 3790
    User: onepointo
    Language: C++
    Result: Accepted
    Time:104 ms
    Memory:2676 kb
****************************************************************/

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 100010 

int pal[N<<1];
char a[N],s[N<<1];
struct Node
{
    int l,r;
    bool operator<(const Node &other)const
    {
        if(l==other.l) return r>other.r;
        return l<other.l;
    }
}t[N];

int manacher()
{
    int len=strlen(a);
    int mx=0,id=0;
    for(int i=1;i<=len;++i) s[i<<1]=a[i-1],s[i<<1|1]='#';
    len<<=1,len+=1;
    s[0]='+',s[1]='#',s[len+1]='-';
    for(int i=1;i<=len;++i)
    {
        if(mx>i) pal[i]=min(mx-i,pal[2*id-i]);
        else pal[i]=1;  
        while(s[i-pal[i]]==s[i+pal[i]]) ++pal[i];  
        if(mx<pal[i]+i) mx=pal[i]+i,id=i;    
    }
    for(int i=1;i<=len;++i)
        t[i].l=i-pal[i]+1,t[i].r=i+pal[i]-1;
    sort(t+1,t+1+len);
    return len;
}

int main()
{
    while(scanf("%s",a)!=EOF)
    {
        int len=manacher(),ans=0;
        int wh=t[1].r,tmp=1,pos=0;
        while(wh<len)
        {
            while(t[tmp].l<=wh) pos=max(pos,t[tmp++].r);
            wh=pos;ans++;
        }
        printf("%d\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值