• manacher---神奇项链


    神奇项链

    时间限制 : - MS   空间限制 : - KB 
    评测说明 : 1s,64m
    问题描述

    母亲节就要到了,小 H 准备送给她一个特殊的项链。
    这个项链可以看作一个用小写字母组成的字符串,每个小写字母表示一种颜色。

    为了制作这个项链,小 H 购买了两个机器。
    第一个机器可以生成所有形式的回文串,第二个机器可以把两个回文串连接起来,而且第二个机器还有一个特殊的性质:
       假如一个字符串的后缀和一个字符串的前缀是完全相同的,那么可以将这个重复部分重叠。例如:aba和aca连接起来,可以生成串abaaca或 abaca。

    现在给出目标项链的样式,询问你需要使用第二个机器多少次才能生成这个特殊的项链。

    输入格式

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

    输出格式

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

    样例输入 1

    abcdcba
    abacada
    abcdef 

    样例输出 1

    0
    2
    5

    样例输入 2

    xuqeytcixfzpzvcacymqncdohedfyowmipplplkyrsaspjliczflordhlbckyiuqxkslntofajs
    amjmaekzbnbwagotspirvjksendltyeeuswefpdcdmmhzomlvkrhtwidlybkvvvebqkmvednaxddeygghrvqfaxwjssvcphcrzeauwlowwdmhacpzbnihgmbypfsblvsyaugkcg

    样例输出 2

    65
    118

    提示

    每个测试数据,输入不超过 5行

    每行的字符串长度小于等于 50000 

    1.通过马拉车找出所有回文子串,把每个回文子串看作一条线段
    2.问题变成选最少的线段将整个区间覆盖,即最小区间覆盖问题。贪心即可。

    #include<stdio.h>
    #include<bits/stdc++.h>
    using namespace std;
    char s[100010];
    int len[100010];//回文串长度
    int n;
    struct Node
    {
        int l,r;
    } a[100010];
    bool cmp(Node a,Node b)//按左端点贪心排序
    {
        return a.l<b.l;
    }
    void Init()
    {
        for(int i=n; i>=1; i--)
        {
            s[i<<1]=s[i];
            s[i<<1|1]='&';
        }
        n=n<<1|1;
        s[0]='%';
        s[1]='&';
        s[n+1]='^';
    }
    void manacher()
    {
        int maxright=0,num=0;
        for(int i=1; i<=n; i++)
        {
            if(i<maxright)
                len[i]=min(len[num*2-i],maxright-i);
            else
                len[i]=1;
            while(s[i+len[i]]==s[i-len[i]])
            {
                len[i]++;
            }
            if(maxright<i+len[i])
            {
                maxright=i+len[i];
                num=i;
            }
        }
    }
    int main()
    {
        while(scanf("%s",s+1)!= EOF)//从第一位开始算 
        {
            n=strlen(s+1);
            Init();
            manacher();
            for(int i=1; i<=n; i++)
            {
                a[i].l=i-len[i]+1;//以i为中心的左长度 
                a[i].r=i+len[i]-1;//以i为中心的右长度
            }
            sort(a+1,a+1+n,cmp);
            int r=0,ans=0,i=1;
            while(i<=n)
            {
                int sum=0;
                while(a[i].l-1<=r&&i<=n)
                {
                    sum=max(sum,a[i].r);
                    i++;
                }
                ans++;//现长
                r=sum;//覆盖完全
                if(r==n)
                {
                    break;
                }
                //ans++;
            }
            cout<<ans-1<<endl;
        }
    }
  • 相关阅读:
    静态方法、类方法、属性方法
    B-tree/B+tree
    支付宝
    七牛云上传视频3
    测试理论
    测试理论
    Xshell上传文件
    iptables增加、删除、修改、查询、保存防火墙策略教程
    docker私有仓库常用命令
    centos7修改主机名
  • 原文地址:https://www.cnblogs.com/CXYscxy/p/11350159.html
Copyright © 2020-2023  润新知